Sign in to follow this  
johnnyBravo

How to do castings so, Vector3 a, b a+=b in c++?

Recommended Posts

Hi, with c++, I am making a Vector3 class. One thing I want to add is to allow the user to add the vectors together. eg Vector3 a(1,1,1), b(3,2,1); a+=b; I heard this is called casting, but I can't find out how to actually do it, like what am I supposed to put in my class? Thanks

Share this post


Link to post
Share on other sites
Casting is different. What you want here is operator overloading. += is an operator, and you can add a function to your class (or separate from your class, if you want) to tell the compiler how that operator works with your class.

You can do it something like this:

class Vector3
{
// ... the rest of your vector class ...
public:
Vector3 &operator += (const Vector3 &rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
};


You don't have to give it that return type, but it is considered normal to do so, because the standard assignment operators for built in types like int will return (as the result of the expression) the value that was assigned.

John B

Share this post


Link to post
Share on other sites
it is not &operator, this means the operator returns a vector3 & which is a reference to a vector3.

Also, the return *this in JohnBSmall's post is used for having multiple operator on the same line like this: vec1 += vec2 += vec3;

hope that helps !
Matt

Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
I see thanks.

So I guess its best to use JohnBSmall's reference way to avoid creating new memory for the variables?

thanks


Only for the assignment operators (including += and friends).

Here is an example of two correct operators for my 2D vector class:


class AV2i
{
// stuff...

inline AV2i& operator+=(const AV2i &v) {x += v.x; y += v.y; return *this;}
inline AV2i operator+(const AV2i &v) const { return AV2i(x+v.x, y+v.y); }

// more stuff...
}





Just a run down of what happens:

- "inline" - tells the compiler to compile the function inline. Not generally necessary these days (particularly MSVC 2003 ignores it).

- AV2i& is returning a reference to a vector, AV2i is returning the vector object itself.

- They both take "const AV2i& v" - this indicates that they take a referene to a vector and that the vector that is passed in is not changed. This is generally the best way to pass unchanging, complicated types around.

- "return *this" dereferences the object that is being added to and returns it.
- "return AV2i(...)" creates a new object and returns it.

Those two different returns and return types are required so your class matches the built-in types in the way that it operates. All the assignment operators should return a reference to "*this", and all the operators arithmatic should return a fresh object by value. (Again, this is generally and if you want to match behaviour of the built-in types).

Share this post


Link to post
Share on other sites
Hey I didn't realise i could call the Vector instance's variables without going through the get/set functions. eg if im inside the vector class, and want the x value from a Vector class instance, i can call just v.x instead of v.getX().

Well anyway, I've got a warning that won't go away:
Quote:

vector.cpp(74) : warning C4172: returning address of local variable or temporary


from the code:

Vector &Vector::operator + (const Vector val) {
return Vector(x+val.x, y+val.y, z+val.z);
}




Any ideas? Thanks

edit:
Oh and also the D3DXVECTOR3 structure can do things like this:
D3DXVECTOR3 abc(1,2,3);
D3DXVECTOR3 v = 5.0f + abc;

Where as mine can't do that, but only can only do:
v = abc + 5.0f;

I don't get what I can do to be able to do that.

Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
Hey I didn't realise i could call the Vector instance's variables without going through the get/set functions. eg if im inside the vector class, and want the x value from a Vector class instance, i can call just v.x instead of v.getX().


Yes you can provided they aren't private variables. If they are private then you need to use v.getX();


Quote:
Original post by johnnyBravo
Well anyway, I've got a warning that won't go away:
vector.cpp(74) : warning C4172: returning address of local variable or temporary

from the code:
*** Source Snippet Removed ***


Thats because you are returning reference to a local variable which you never ever want to do. The reason is, the value is in scope only until the function is executing, after that you will be pointing to junk. If you want to return a local variable, do a copy. The right way to do what you are doing is.


Vector Vector::operator + (const Vector val) {
return Vector(x+val.x, y+val.y, z+val.z);
}




If you want to return a reference, do it the way JohnBSmall is doing it. In Andrews post you can see this subtle difference already.

Hope this helps.






Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
Oh and also the D3DXVECTOR3 structure can do things like this:
D3DXVECTOR3 abc(1,2,3);
D3DXVECTOR3 v = 5.0f + abc;

Where as mine can't do that, but only can only do:
v = abc + 5.0f;

I don't get what I can do to be able to do that.

First of all, are you sure it is an addition? You probably meant multiplication.

Think about it like this. When you are making your operator that takes a float and scales your vector, you probably have something similar to this:
Vector3 Vector3::operator * (float s)
{ return Vector3(x*s, y*s, z*s); }

This is equivelant to a global function like this:
Vector3 MultiplyVector3ByScalar(const Vector3& lhs, float rhs)
{ return Vector3(lhs.x*rhs, lhs.y*rhs, lhs.z*rhs); }

This means that you can only multiply the vector by a scalar to the right of it.

In order to multiply it by a scalar to the left, you need to make a global operator, like so:

class Vector3 {
...
friend Vector3 operator * (float lhs, const Vector3& rhs);

float x, y, z;
}

inline Vector3 operator * (float lhs, const Vector3& rhs)
{ return Vector3(rhs.x*lhs, rhs.y*lhs, rhs.z*lhs); }

Now, you can multiply by a scalar to the left and the right.

Vector3 test1(3.0f, 4.0f, 5.0f);

Vector3 test2 = test1 * 3.0f; // Multiply by a scalar to the right
test1 = -3.0f * test2; // Multiply by a scalar to the left


Hope I wasn't beaten to the reply ;).

[EDIT] Forgot the inline keyword and added a little more to the explanation. And, I guess I wasn't beaten to the reply.

Slaru

Share this post


Link to post
Share on other sites
Quote:
Yes you can provided they aren't private variables. If they are private then you need to use v.getX();


Private refers to the class, not the instance. For example:

class X
{
private:
int a;
public:
void somefunc(X someotherx)
{
a += someotherx.a; //Fine, even though the variable is private.
}
};


Also, MATHMATICAL VECTORS SHOULD NOT HAVE GET AND SET FUNCTIONS FOR THE DIMENSIONAL COMPONENTS.

Share this post


Link to post
Share on other sites
Quote:
Also, MATHMATICAL VECTORS SHOULD NOT HAVE GET AND SET FUNCTIONS FOR THE DIMENSIONAL COMPONENTS.


Oh, I thought I should follow the class convention....so I should make them public instead?

thx

edit:

Oh and Slaru, I'm getting this error:
Quote:

vector.cpp(121) : error C2511: 'Vector Vector::operator *(float,const Vector &)' : overloaded member function not found in 'Vector'
c:\my\new\space\vector.h(2) : see declaration of 'Vector'

for this code:

inline Vector Vector::operator * (float lhs, const Vector& rhs) { //this line is the problem
return Vector(rhs.x*lhs, rhs.y*lhs, rhs.z*lhs);
}


Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
Quote:
Also, MATHMATICAL VECTORS SHOULD NOT HAVE GET AND SET FUNCTIONS FOR THE DIMENSIONAL COMPONENTS.


Oh, I thought I should follow the class convention....so I should make them public instead?

thx


Probably not; the constructors and mathematical operators should represent a sufficient interface. Assume they will until your calling code proves a need.

Share this post


Link to post
Share on other sites
Most vector classes I've used and seen (including my own) make the components public. Definitely make them public for ease of use.

Your get/set function would just return/set the actual component to whatever is passed/requested:

float Vector3::GetX() const { return x; }
void Vector3::SetX(float ix) { x = ix; }
...

So, wouldn't you rather just type Vec.x instead of Vec.GetX()?

Unless whenever you set the value of the component you would like to have the vector renormalized or something else, it isn't needed.

Slaru

Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
Slaru, I'm getting this error:
Quote:

vector.cpp(121) : error C2511: 'Vector Vector::operator *(float,const Vector &)' : overloaded member function not found in 'Vector'
c:\my\new\space\vector.h(2) : see declaration of 'Vector'

for this code:
inline Vector Vector::operator * (float lhs, const Vector& rhs) { //this line is the problem 
return Vector(rhs.x*lhs, rhs.y*lhs, rhs.z*lhs);
}

Yes, that is correct. You should be getting that error. The "Vector3 operator * (float lhs, const Vector3& rhs)" function shouldn't be a member function of Vector3, it should be a global function. Your code should be like this:

// No Vector3:: because it isn't a member function of Vector3
inline Vector operator * (float lhs, const Vector& rhs) { // Here is the corrected line
return Vector(rhs.x*lhs, rhs.y*lhs, rhs.z*lhs);
}

Slaru

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Probably not; the constructors and mathematical operators should represent a sufficient interface. Assume they will until your calling code proves a need.

I disagree here. Vector classes is one of the few places where making member data (in this case: vector components) public is actually a good idea.

Share this post


Link to post
Share on other sites
I see, when using the gets, i get an error:
Quote:

error C2662: 'Vector::getX' : cannot convert 'this' pointer from 'const Vector' to 'Vector &'
Conversion loses qualifiers
error C2662: 'Vector::getY' : cannot convert 'this' pointer from 'const Vector' to 'Vector &'
Conversion loses qualifiers
error C2662: 'Vector::getZ' : cannot convert 'this' pointer from 'const Vector' to 'Vector &'
Conversion loses qualifiers


inline Vector operator * (float lhs, const Vector& rhs) {
return Vector(rhs.getX()*lhs, rhs.getY()*lhs, rhs.getZ()*lhs);
}

Share this post


Link to post
Share on other sites
Quote:
Original post by johnnyBravo
I see, when using the gets, i get an error:
Quote:

error C2662: 'Vector::getX' : cannot convert 'this' pointer from 'const Vector' to 'Vector &'
Conversion loses qualifiers
error C2662: 'Vector::getY' : cannot convert 'this' pointer from 'const Vector' to 'Vector &'
Conversion loses qualifiers
error C2662: 'Vector::getZ' : cannot convert 'this' pointer from 'const Vector' to 'Vector &'
Conversion loses qualifiers

*** Source Snippet Removed ***

Why are you using those get functions? Don't use them, the are utterly useless. Just make the components public and do "rhs.x" etc.

I agree with Andrew Russell, the components of a vector class should be made public. Normally, for a class you'd want to hide the actual data, but this is an instance where hiding it and providing get/set functions is useless.

Slaru

Share this post


Link to post
Share on other sites
The reason that you get those errors (cannot convert 'this' pointer from 'const Vector' to 'Vector &' Conversion loses qualifiers), is because the get functions are not const.

As I suggested - you should not have them in the first place - just make the components public.

As a lesson on how to make your get function const:


class foo
{
int bar;
public:
int GetBar() const { return bar; }
};



Note the use of the word const after the arguments, before the definition.

The const keyword indicates that the function will not change any of the member data. You can't call a non-const function on a const object.

This is because a const object indicates that the data will not be changed. Calling a non-const function on it could cause the data to be changed (whereas, a const function tells the compiler it won't).


See also, my own + and += operators up the page - they show propper use of the const keyword on +, but not on +=.

Share this post


Link to post
Share on other sites
Quote:
Original post by Andrew Russell
- "inline" - tells the compiler to compile the function inline. Not generally necessary these days (particularly MSVC 2003 ignores it).


If you define a member function inside a class its implicitly inline.

Also its best to make general arithmetic operators in terms of arithmetic assignment operators:


struct foo {

foo& operator+=(const foo& f) { ... }
foo operator+(const foo& f) const { return foo(f) += f; }

};


Quote:
Original post by Slaru
When you are making your operator that takes a float and scales your vector, you probably have something similar to this:
Vector3 Vector3::operator * (float s)
{ return Vector3(x*s, y*s, z*s); }

This is equivelant to a global function like this:
Vector3 MultiplyVector3ByScalar(const Vector3& lhs, float rhs)
{ return Vector3(lhs.x*rhs, lhs.y*rhs, lhs.z*rhs); }


Well no its a member function in this case, if you explicitly invoke that operator its looks like this:


Vector3 c = a.operator*(b);


Quote:
Original post by Slaru
Why are you using those get functions? Don't use them, the are utterly useless. Just make the components public and do "rhs.x" etc.


Another reason to make those data members public is to make your vector type a POD-type therefore certain algorithms can take advantage of optimizations for containers of your vector and can be used with some C functions you should not use for non-POD types. POD-types are bit-wise copyable.

To be a POD-type, it should have all data members public, all data members should be POD-types aswell, no user-declared copy constructor, no user-declared assignement operator (excludes other type of assignment operators such as arithmetic assignment), no user-declared destructor.

[Edited by - snk_kid on May 31, 2005 4:20:15 AM]

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