- A good Point/Size implementation? Re-using with different names - 11 Updates
- No public class members? - 4 Updates
Victor Bazarov <v.bazarov@comcast.invalid>: Dec 11 12:16PM -0500 On 12/11/2014 11:33 AM, JiiPee wrote: > I am creating these Point (x, y) and Size (width, height) classes. > Because they are pretty much the same thing I would like to re-use the > Point class. In what way would you "re-use" it? > I could use width and height? > Is there any way to hide the width and height for point and x, y for Size? > [..] You could have Size class derive privately from Point and define the 'width' and 'height' in it as _references_ to the base class' members 'x' and 'y', respectively. Initialize the refs in the Size's c-tor. V -- I do not respond to top-posted replies, please don't ask |
JiiPee <no@notvalid.com>: Dec 11 06:21PM On 11/12/2014 17:16, Victor Bazarov wrote: >> Because they are pretty much the same thing I would like to re-use the >> Point class. > In what way would you "re-use" it? So that Size would somehow use Point's code. So when I say: Size s = Size(2,3); all this code is from Point class. So Size is just another name for Point kind of. The only difference being that I want Size to have width instead of x member. > 'width' and 'height' in it as _references_ to the base class' members > 'x' and 'y', respectively. Initialize the refs in the Size's c-tor. > V Ok, I actually tried this already but got problems with return values: CSize operator + (const CSize& point) const { return Point2D<T>::operator + (point); } its asking that + operator. So I have to call the parent class. But the return value is Point2D :). I have to scratch my head a bit now how to do this.. :) |
JiiPee <no@notvalid.com>: Dec 11 06:25PM On 11/12/2014 18:21, JiiPee wrote: > its asking that + operator. So I have to call the parent class. But > the return value is Point2D :). I have to scratch my head a bit now > how to do this.. :) Any hint how to return the Point2D + operator return value as CSize type? the compiler is complaining about this. |
JiiPee <no@notvalid.com>: Dec 11 06:51PM Ok, because it was complaining I arranged what it asked. So, I set it: CSize operator + (const CSize& point) const { return static_cast<CSize>(Point2D<T>::operator + (point)); } But now its complaining that copy constructor: CSize::CSize(Point2D&) is missing. So I added it: CSize(const Point2D<T>& point) : Point2D<T>(point) { } and it works. Is this the way to do it? I hope its not calling copy constructors now like 3 times though... I guess the compiler will sort it out, hopefully. |
Victor Bazarov <v.bazarov@comcast.invalid>: Dec 11 02:19PM -0500 On 12/11/2014 1:21 PM, JiiPee wrote: > all this code is from Point class. So Size is just another name for > Point kind of. The only difference being that I want Size to have width > instead of x member. [..] My partially rhetorical question was in an attempt to draw your attention that a Size *is not* a Point. You will probably see it later when you add some functionality to Point, which you don't want to see in Size, and vice versa. What you need is the common base class for those. Find a copy of James Coplien's "Advanced C++" (IIRC it was published in 1991) and read it carefully. A quick hint: don't try to substitute one class for another if there is no true substitution between them. Here is one example of what some consider a fault in the design. As is often suggested, a point in N-dimensional space *is a* vector in that space. However, when some linear algebra interface is developed, we need to remember that affine transformations when applied to a point produce a different result than those applied to a vector (the translation should be ignored for the latter transform). So, I have seen more than once typedef vectorNd pointNd; and then somewhere ... pointNd xformAsPoint(const pointNd &) const; along with vectorNd xformAsVector(const vectorNd &) const; So, what's wrong, you might ask. Here is what's wrong. First off, I want those two types to be distinct and have two *overloaded* functions 'xform' ("transform"), one for *a point* and one for *a vector*. Second, I want to never be able to pass a point where a vector is expected (and vice versa), so not to make a mistake. IOW, I want to be able to require a cast made when one is converted into (treated as) the other. Such requirements prevent mistakes that the compiler cannot catch. So, in your case, I strongly recommend figuring out what is common between a Point and a Size, extracting that common portion into another class and using that class as a base for both Point and Size. Constructors are now (in C++11, and later) inherited, so you should be able to do what you *already* want, i.e. to share the constructor between those two types (three types, actually). But don't rush into implementation. Design them first. Correctly. V -- I do not respond to top-posted replies, please don't ask |
JiiPee <no@notvalid.com>: Dec 11 07:33PM On 11/12/2014 19:19, Victor Bazarov wrote: > attention that a Size *is not* a Point. You will probably see it > later when you add some functionality to Point, which you don't want > to see in Size, and vice versa. Yes, but at least currently all they functions are the same. But ye, in the future they might divert. Although if one wants to keep them simple they might never change. > want to be able to require a cast made when one is converted > into (treated as) the other. > Such requirements prevent mistakes that the compiler cannot catch. deep... have to think about that :) > So, in your case, I strongly recommend figuring out what is common > between a Point and a Size, extracting that common portion into > another class and using that class as a base for both Point and Size. Yes, I was already thinking the same. Agree... I had just one problem: how to call that base class?? :) How would you call it? Yes this is indeed a good solution. > between those two types (three types, actually). But don't rush into > implementation. Design them first. Correctly. > V Yes. |
JiiPee <no@notvalid.com>: Dec 11 07:46PM On 11/12/2014 19:33, JiiPee wrote: > Yes, I was already thinking the same. Agree... I had just one problem: > how to call that base class?? :) How would you call it? Yes this is > indeed a good solution. I guess just "Vector2D" would be a good name? The only problem is that its not really a full on vector, its kind of limited vector. So maybe: "SimpleVector2D"? |
Paavo Helde <myfirstname@osa.pri.ee>: Dec 11 03:18PM -0600 >> On 12/11/2014 11:33 AM, JiiPee wrote: >>> I am creating these Point (x, y) and Size (width, height) classes. >>> Because they are pretty much the same thing I would like to re-use the > all this code is from Point class. So Size is just another name for > Point kind of. The only difference being that I want Size to have width > instead of x member. If this were the only difference, then having different names for the members would be just an obfuscation, introducing additional complexity without any benefits. In this case it would be just better to rename the class to PointOrSize or IntPair or something like that. But in general you cannot avoid some code duplication. Avoiding code duplication is a tool to achieve the goal (a better program), not the goal itself. For example, you may notice that in your code there are many long keywords like "return" repeated all over. Does it make sense to #define R return and use R instead to reduce code duplication? No, because this is not the goal! Cheers Paavo |
Bo Persson <bop@gmb.dk>: Dec 11 10:19PM +0100 On 2014-12-11 20:33, JiiPee wrote: > Yes, but at least currently all they functions are the same. But ye, in > the future they might divert. Although if one wants to keep them simple > they might never change. But you don't want to use the same class for all objects containing two int's, do you? Otherwise you could use std::pair<int, int> from the standard library. Conceptually a point and a size are totally different, so should be different types. Trying for code reuse at this level is a serious case of premature optimization. Instead, trust your compiler to sort this out for you! Bo Persson |
JiiPee <no@notvalid.com>: Dec 11 09:30PM On 11/12/2014 21:19, Bo Persson wrote: > But you don't want to use the same class for all objects containing > two int's, do you? Otherwise you could use std::pair<int, int> from > the standard library. But the point has many functions. pair could not do that. Or you mean putting pair inside a class? > Conceptually a point and a size are totally different, so should be > different types. But I think they have a lot of similar functions. I already did that. And I put 11 member functions. I dont think much more will come, but maybe could create a common base class: PointSize.... or something. No, its only for point and size and similar things, not all pairs > Trying for code reuse at this level is a serious case of premature > optimization. Instead, trust your compiler to sort this out for you! I dont know... I just dont like writing same code twice :). I like the trick using the same code. Unless you have a very good reason not to do it.. Here are the common things: Point2D() = default; Point2D(const T& pointXY); Point2D(const T& pointX, const T& pointY); Point2D(const Point2D& point) = default; Point2D& operator = (const Point2D& point) = default; Point2D& operator = (const T& pointXY); Point2D operator + (const Point2D& point) const; Point2D operator - (const Point2D& point) const; Point2D operator + (const T& pointXY) const; Point2D operator - (const T& pointXY) const; Point2D operator * (const T& pointXY) const; Point2D operator / (const T& pointXY) const; Point2D operator - () const; T x; T y; |
JiiPee <no@notvalid.com>: Dec 11 09:32PM On 11/12/2014 21:18, Paavo Helde wrote: > goal itself. For example, you may notice that in your code there are many > long keywords like "return" repeated all over. Does it make sense to > #define R return :) > and use R instead to reduce code duplication? No, because this is not the > goal! Its more readable |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 11 05:06PM On 11/12/2014 00:17, JiiPee wrote: > But seems to me that most library implementators prefer 1) version, even > Microsoft. > So a poll: how many or you chose a) and how man b)?? What you present in b) is neither a getter or a setter and practically has no difference to public member variables. Getter/setter would be: int X() const { return x; } void setX(int aX) { x = aX; } /Flibble |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 11 05:09PM On 11/12/2014 00:17, JiiPee wrote: > But seems to me that most library implementators prefer 1) version, even > Microsoft. > So a poll: how many or you chose a) and how man b)?? All member variables that contribute to a class's invariant should be private modulo const member variables. /Flibble |
"Öö Tiib" <ootiib@hot.ee>: Dec 11 10:03AM -0800 On Thursday, 11 December 2014 10:09:28 UTC+2, JiiPee wrote: > But lets say you want to print/log to a file also something when x==0, > that would not be possible I guess? For that we would need the setX > -function. Indeed, if you want to write some run-time sanity checks or debug tracing or logging for (at least some of) occasions when value of member changes (or is read) then that sort of debugging is easiest to do with accessor functions. I trust that is what Sutter had in mind. > a matter of taste as well I guess. But if most of the professionals use > in libs publics here, then I guess its good to follow them...they all > have been thinking about this and did their desisions. On general case neither public accessor member functions nor public member data do make sense. Every mutable member is usually related with rest of the data that is managed by class. There are always dependencies. Exposing it results that the class has effectively dropped responsibility to manage its data. For example about such dependencies imagine that "std::vector" had ... 3 getters: 'get_start()', 'get_finish()', 'get_end_of_storage()' and 3 setters: 'set_start(s)', 'set_finish(f)', 'set_end_of_storage(e)'. That is it. What else you need? It is all data members it has. Indeed, such "vector" would be worthless. The classes that have lot of getters and setters tend to be as worthless as rule. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Dec 11 08:19PM On Thu, 2014-12-11, JiiPee wrote: ... > So far all libraries I have checked (3-4) use public x and y. For > example b2Vec2 in physics library Box2D also doing it. So seems like > putting them public seems to be prefered among library makers But we're not library makers. Most classes we write will only be used by other code which is under our control, so it's easy for us to change the interface when needed. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment