Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A good Point/Size implementation? Re-using with different names

58 views
Skip to first unread message

JiiPee

unread,
Dec 11, 2014, 11:34:13 AM12/11/14
to
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. If I use typedef it works, but then Size would get x and y,
but I want width and height instead. I was thinking to use union. It
would do the job, the only small issue is then that Point also has them
(not a major issue for me though). Is there any other way to do this so
I could use width and height?

Is there any way to hide the width and height for point and x, y for Size?

I know I could use getters and setters, but I would rather not use it here.

template <class T>
class Point2D
{
public:
Point2D(const Point2D& point) = default;
// other functions
// ...
union
{
T x;
T width;
};
union
{
T y;
T height;
};
};


Victor Bazarov

unread,
Dec 11, 2014, 12:16:42 PM12/11/14
to
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?

> If I use typedef it works, but then Size would get x and y,
> but I want width and height instead. I was thinking to use union. It
> would do the job, the only small issue is then that Point also has them
> (not a major issue for me though). Is there any other way to do this so
> 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

unread,
Dec 11, 2014, 1:21:37 PM12/11/14
to
On 11/12/2014 17:16, Victor Bazarov wrote:
> 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?

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.

>
> > If I use typedef it works, but then Size would get x and y,
>> but I want width and height instead. I was thinking to use union. It
>> would do the job, the only small issue is then that Point also has them
>> (not a major issue for me though). Is there any other way to do this so
>> 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

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

unread,
Dec 11, 2014, 1:26:12 PM12/11/14
to
Any hint how to return the Point2D + operator return value as CSize
type? the compiler is complaining about this.

JiiPee

unread,
Dec 11, 2014, 1:51:28 PM12/11/14
to
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

unread,
Dec 11, 2014, 2:19:25 PM12/11/14
to
On 12/11/2014 1:21 PM, JiiPee wrote:
> On 11/12/2014 17:16, Victor Bazarov wrote:
>> 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?
>
> 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. [..]

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.

JiiPee

unread,
Dec 11, 2014, 2:34:15 PM12/11/14
to
On 11/12/2014 19:19, Victor Bazarov wrote:
> On 12/11/2014 1:21 PM, JiiPee wrote:
>> On 11/12/2014 17:16, Victor Bazarov wrote:
>>> 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?
>>
>> 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. [..]
>
> 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.

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.
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.

>
> 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

Yes.

JiiPee

unread,
Dec 11, 2014, 2:47:00 PM12/11/14
to
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

unread,
Dec 11, 2014, 4:19:06 PM12/11/14
to
JiiPee <n...@notvalid.com> wrote in news:Ggliw.34306$812....@fx20.am4:

> On 11/12/2014 17:16, Victor Bazarov wrote:
>> 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?
>
> 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.

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

unread,
Dec 11, 2014, 4:19:33 PM12/11/14
to
On 2014-12-11 20:33, JiiPee wrote:
> On 11/12/2014 19:19, Victor Bazarov wrote:
>>
>> 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.
>
> 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

unread,
Dec 11, 2014, 4:30:53 PM12/11/14
to
On 11/12/2014 21:19, Bo Persson wrote:
> On 2014-12-11 20:33, JiiPee wrote:
>> On 11/12/2014 19:19, Victor Bazarov wrote:
>>>
>>> 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.
>>
>> 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.

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

unread,
Dec 11, 2014, 4:32:38 PM12/11/14
to
:)

>
> and use R instead to reduce code duplication? No, because this is not the
> goal!
>
Its more readable


Öö Tiib

unread,
Dec 12, 2014, 6:47:43 AM12/12/14
to
On Thursday, 11 December 2014 18:34:13 UTC+2, 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. If I use typedef it works, but then Size would get x and y,
> but I want width and height instead. I was thinking to use union. It
> would do the job, the only small issue is then that Point also has them
> (not a major issue for me though). Is there any other way to do this so
> I could use width and height?

The "distance" and "size" are similar (same) in sense that they
are relative (vector) values. "point" however is absolute (location)
value. Therefore there are different operations that may make
sense for us to do with one or other and also the results are
different.

For example it does make sense to add distance to point and we
will get other point. It makes sense to add distance to distance
and we get resulting distance. However it does not make sense
to add point to point. Similarly we may multiply (or divide)
distance with scalar and get scaled distance. However it does
not make sense to multiply point with scalar.

Therefore if you mix (or merge) "point" and "size" up then what
you will get is nonsense because the meaning of those terms is
lost.

There are plenty of tools in standard library to avoid writing
meaningless or confusing classes. For example if you want to bind
two values of type 'T' together but do not want any meaning bound
to that data then you can use 'std::pair<T>' or 'std::array<T,2>'
or 'std::tuple<T,T>'. These all work fine and efficiently with
some difference in usage syntax (so pick what fits your taste).
Usage of such abstract constructs documents that developer has
now taken responsibility to follow and check any "meaning" at
places of usage.

JiiPee

unread,
Dec 12, 2014, 7:41:12 AM12/12/14
to
On 12/12/2014 11:47, Öö Tiib wrote:
> On Thursday, 11 December 2014 18:34:13 UTC+2, 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. If I use typedef it works, but then Size would get x and y,
>> but I want width and height instead. I was thinking to use union. It
>> would do the job, the only small issue is then that Point also has them
>> (not a major issue for me though). Is there any other way to do this so
>> I could use width and height?
> The "distance" and "size" are similar (same) in sense that they
> are relative (vector) values. "point" however is absolute (location)
> value. Therefore there are different operations that may make
> sense for us to do with one or other and also the results are
> different.
>
> For example it does make sense to add distance to point and we
> will get other point. It makes sense to add distance to distance
> and we get resulting distance. However it does not make sense
> to add point to point. Similarly we may multiply (or divide)
> distance with scalar and get scaled distance. However it does
> not make sense to multiply point with scalar.

hmmm, the thing is that I was planning to use Point as a (mathematical-)
vector. But ye, thinking the correct name should be consider here, as
Point is not necessary the same as a mathematical vector. I ll have to
think about this. Although I think in computer graphics its is used a
lot that Point means vector as well. Or at least they are used as if
they are vectors. But I ll have to think about this...

Should I then create a "Vector" instead?

JiiPee

unread,
Dec 12, 2014, 8:00:50 AM12/12/14
to
On 12/12/2014 11:47, Öö Tiib wrote:
> On Thursday, 11 December 2014 18:34:13 UTC+2, 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. If I use typedef it works, but then Size would get x and y,
>> but I want width and height instead. I was thinking to use union. It
>> would do the job, the only small issue is then that Point also has them
>> (not a major issue for me though). Is there any other way to do this so
>> I could use width and height?
> The "distance" and "size" are similar (same) in sense that they
> are relative (vector) values. "point" however is absolute (location)
> value. Therefore there are different operations that may make
> sense for us to do with one or other and also the results are
> different.
>
> For example it does make sense to add distance to point and we
> will get other point. It makes sense to add distance to distance
> and we get resulting distance. However it does not make sense
> to add point to point. Similarly we may multiply (or divide)
> distance with scalar and get scaled distance. However it does
> not make sense to multiply point with scalar.
>
>

I was just thinking it (as a mathematician), and you are actually right!
Point is actually a one dimensional thing, and vector is in 2 dimension.
So probably the correct representation would be:

class Point
{
int x,y;
void setPos(int newX, int newY) {x=newX, y=newY}
// ... other 1 demensinal functions
};

class Vector : public Point
{
void multiplyByScalar(int a);
};

You got me thinking :). hmmm, I think I have to re-arrange my classes
now. This was a good observation. Only thing is that have to think about
the Size.... what is its base class...

JiiPee

unread,
Dec 12, 2014, 8:17:44 AM12/12/14
to
On 12/12/2014 11:47, Öö Tiib wrote:
So at the moment am thinking of having Point as a base class and inherit
Vector from it. Size maybe needs to be a totally different class,
although then I must multiply some code.

Paavo Helde

unread,
Dec 12, 2014, 11:53:54 AM12/12/14
to
JiiPee <n...@notvalid.com> wrote in news:VFBiw.132827$oJ1....@fx28.am4:

> I was just thinking it (as a mathematician), and you are actually
> right! Point is actually a one dimensional thing, and vector is in 2
> dimension. So probably the correct representation would be:
>
> class Point
> {
> int x,y;
> void setPos(int newX, int newY) {x=newX, y=newY}
> // ... other 1 demensinal functions
> };
>
> class Vector : public Point
> {

As you just said, Vector is not a Point. Thus it makes no sense to derive
Vector (publicly) from Point (Liskov principle is violated!). Your Vector
just inherited the setPos() member function which now can be called on
it. What would it mean? A mathematical vector either does not have any
position, or maybe it has two of them (start and end), if that's what you
want to describe.

IOW, there is no need to abuse inheritance just to avoid code
replication. There are other ways to deal with code replication, starting
from extracting the code into a separate ordinary function.


hth
Paavo

JiiPee

unread,
Dec 12, 2014, 2:02:47 PM12/12/14
to
On 12/12/2014 16:53, Paavo Helde wrote:
> JiiPee <n...@notvalid.com> wrote in news:VFBiw.132827$oJ1....@fx28.am4:
>
>> I was just thinking it (as a mathematician), and you are actually
>> right! Point is actually a one dimensional thing, and vector is in 2
>> dimension. So probably the correct representation would be:
>>
>> class Point
>> {
>> int x,y;
>> void setPos(int newX, int newY) {x=newX, y=newY}
>> // ... other 1 demensinal functions
>> };
>>
>> class Vector : public Point
>> {
> As you just said, Vector is not a Point. Thus it makes no sense to derive
> Vector (publicly) from Point (Liskov principle is violated!).

true. Vector is not a type of point.

> Your Vector
> just inherited the setPos() member function which now can be called on
> it. What would it mean? A mathematical vector either does not have any
> position, or maybe it has two of them (start and end), if that's what you
> want to describe.
>
> IOW, there is no need to abuse inheritance just to avoid code
> replication. There are other ways to deal with code replication, starting
> from extracting the code into a separate ordinary function.
>
>

good idea. I will actually now think of doing this , might be best. But
there are a lot of functions doing the same thing so I really want to
re-use them. but this function thing might be a solution...

0 new messages