Sign in to follow this  
Daishim

Operator Overloaded Sub Objects

Recommended Posts

I seem to be having some trouble with objects that are templated and have overloaded operators as being members of another object. For example, I have a 3D point object, that holds the point/particles (X,Y,Z) position. It is templated to support different coordinate storage types (float, double, int). If I want to create a vector between the two points, I subtract the point a from point b and the result is then stored in a vector object, which is also templated. This works fine. Now, let's say I have a triangle object, where the I have points A,B,C. Points A,B, and C are of the point object type mentioned above. When I trying to perform the same subtraction to create a vector between the two points, the compiler generates an error stating that it cannot find a suitable subtraction operator method to handle the situation. So given:
template<class T_POINT_TYPE>

// 3D point object
struct G_POINT
{
	T_POINT_TYPE X;
	T_POINT_TYPE Y;
	T_POINT_TYPE Z;

	G_POINT(void) : X(0), Y(0), Z(0) { /* Empty */ }
	G_POINT(const G_POINT<T_POINT_TYPE> &New) : X(New.X), Y(New.Y), Z(New.Z) { /* Empty */ }
	G_POINT(const T_POINT_TYPE Init_X, const T_POINT_TYPE Init_Y, const T_POINT_TYPE Init_Z) : X(Init_X), Y(Init_Y), Z(Init_Z) { /* Empty */ }

	const G_POINT &operator=(const G_POINT<G_Float> &New) {X = New.X; Y = New.Y; Z = New.Z; return *this;}

	const G_POINT &operator-(const G_POINT<G_Float> &Right) {X -= Right.X; Y -= Right.Y; Z -= Right.Z; return *this;}

};

struct G_TRIANGLE
{
        G_POINT<G_Float> A;
        G_POINT<G_Float> B;
        G_POINT<G_Float> C;
};



This works:
int func(void)
{
        G_POINT Point_A(4.0, 5.0, 6.0);
        G_POINT Point_B(1.5, 2.5, 3.5);
        G_VECTOR<G_Float> Vector_A = Point_B - Point_A;
}



But this does not:
int func(G_TRIANGLE &Triangle)
{
        G_VECTOR<G_Float> Vector = Triangle.B - Triangle.A;
}



Any ideas as to why the operators are not working the same when objects are sub objects? [Edited by - Daishim on September 5, 2006 8:40:42 PM]

Share this post


Link to post
Share on other sites
Triangle.A and Triangle.B are both of type G_POINT<G_Float>. The result of G_POINT<G_Float>::operator -(const G_POINT<G_Float> &) is a G_POINT<G_Float>, but you assign it to a variable of type G_VECTOR<G_Float>.

Do your G_VECTOR<G_Float> class have a constructor taking a G_POINT<G_Float>?

Share this post


Link to post
Share on other sites
	const G_POINT &operator-(const G_POINT<G_Float> &Right) {X -= Right.X; Y -= Right.Y; Z -= Right.Z; return *this;}



What you are doing above is often known as "evil".

Your operator- is non-const, and behaves like an operator-=.

To fix:

const G_POINT &operator-=(const G_POINT<G_Float> &Right) {X -= Right.X; Y -= Right.Y; Z -= Right.Z; return *this;}

G_POINT operator-(const G_POINT<G_Float> &Right) const {G_POINT tmp = *this; return tmp-=Right;}



I would be willing to bet you "goofed" again, and the operator- is failing for lack of a const.

Second, it is common that ALL_CAPS_WITH_UNDERSCORES_MEANS_A_MACRO, and not a template.

...

Next, it helps if you can post a minimium case of code that compiles and contains your problem. What you posted is non-compiling code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
It might also help if you explained your rational for having seperate point and vector classes.


Naw, that makes perfect sense. Points and vectors are different things.

They both happen to be "vector fields" of the same dimension.

But if you add two points together, you have a bug. If you scale a point, you have a bug. The vector "0" is special -- but the point "0" is not special. If you use the point "0" you have a bug. If you use the vector "0" you do not have a bug.

A vector is a difference of points.

By having the static type system distinguish between them, you can catch some bugs. Sort of like rolling dimensional analysis into the static type system -- it helps sometimes. :)

Share this post


Link to post
Share on other sites
The problem was the overloaded operators not being const, due to an oversight in my hurried creation. Pays to slow down I guess.

I also chose to seperate points and vectors for that exact reason above.

Share this post


Link to post
Share on other sites
I have never yet seen a case where I didn't want to be able to apply the same set of functionality to a vector and a point.

I DO what to scale points (grab the corner, multiple it by a scale factor, reset it) ... I DO want to add, difference, average two points (average of 2 points is there midpoint, difference of two points is the line segment which would connect them - and usefull for collision detection).

I think you have fallen into the OO trap without realizing it. You have made distinct objects out of concepts that are fundamentally one idea with multiple names. The fundamental advancement of math and science is to unify all that may be unified - and nothing that may not. So if the answer to the question "when would it not work to use an X instead of a Y" would be "never" then they should be one class.

Share this post


Link to post
Share on other sites
Furthermore, you need not duplicate code to differentiate. Make it a simple template with an integer template parameter, then


typedef vector_3<float, true> Vector3;
typedef vector_3<float, false> Point3;


Differentiating mathmatical types can have benifits - but this isn't one of those cases, because a point IS A vector.

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
I have never yet seen a case where I didn't want to be able to apply the same set of functionality to a vector and a point.

I DO what to scale points (grab the corner, multiple it by a scale factor, reset it) ... I DO want to add, difference, average two points (average of 2 points is there midpoint, difference of two points is the line segment which would connect them - and usefull for collision detection).


The difference of two points is a vector.

P=P+V // you can use a vector and add it to a point
V=P-P // vectors are differences between points
V=S*V // vectors can be scaled
V=0 // the zero vector makes sense

You don't want to scale a point. You want to take a set of points, subtract away a point from each element of the set and get a set of vectors, scale the set of vectors, then add a point to each element of the set and get a set of points back.

The average of two points:
V0 = (P2-P1)
V0 = V0/2
Pavg = P1 + V0

Quote:
I think you have fallen into the OO trap without realizing it. You have made distinct objects out of concepts that are fundamentally one idea with multiple names. The fundamental advancement of math and science is to unify all that may be unified - and nothing that may not. So if the answer to the question "when would it not work to use an X instead of a Y" would be "never" then they should be one class.


The thing is, from a mathematical standpoint, points and vectors can quite rightly be viewed as members of different spaces.

The space of positions has no origin. There is no location in 3space that is special -- if you take all of 3space, and translate it left 500 km, you get the same space back.

The space of differences in position has an origin. Two things being at the same spot makes sense. If you take the space of differences in location, and translate it left 500 km, you get nonsense.

You missed another question. If "is there an operation that makes sense on X but not on Y", then you don't want X and Y to be the same class.

The advantage of splitting points and vectors is you get your compiler to make certain you aren't a dumbass and scale a point, or take a difference between a vector and a point.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this