typedef struct tVector3
{
tVector3() {} // constructor
tVector3 (float new_x, float new_y, float new_z) // initialize constructor
{x = new_x; y = new_y; z = new_z;}
tVector3 operator+(tVector3 vVector) {return tVector3(vVector.x+x, vVector.y+y, vVector.z+z);}
tVector3 operator-(tVector3 vVector) {return tVector3(x-vVector.x, y-vVector.y, z-vVector.z);}
tVector3 operator*(float number) {return tVector3(x*number, y*number, z*number);}
tVector3 operator/(float number) {return tVector3(x/number, y/number, z/number);}
float x, y, z;
}tVector3;
typedef struct tPlan2
{
tPlan2() {}
tPlan2(tVector3 new_a, tVector3 new_b)
{a= new_a; b=new_b;}
tPlan2 operator+(tPlan2 vPlan) {return tPlan2(vPlan.a+a, vPlan.b+b);}
tPlan2 operator-(tPlan2 vPlan) {return tPlan2(a-vPlan.a, b-vPlan.b);}
tPlan2 operator*(float num) {return tPlan2(num*a, num*b);}
tPlan2 operator/(float num) {return tPlan2(a/num, b/num);}
tVector3 a;
tVector3 b;
}tPlan2;
typedef struct tPlan4
{
tPlan4() {}
tPlan4(tVector3 new_a, tVector3 new_b, tVector3 new_c, tVector3 new_d)
{a=new_a; b=new_b; c=new_c; d=new_d;}
tPlan4 operator+(tPlan4 vPlan) {return tPlan4(vPlan.a+a, vPlan.b+b, vPlan.c+c, vPlan.d+d);}
tPlan4 operator-(tPlan4 vPlan) {return tPlan4(vPlan.a-a, vPlan.b-b, vPlan.c-c, vPlan.d-d);}
tPlan4 operator*(float num) {return tPlan4(num*a, num*b, num*c, num*d);}
tPlan4 operator/(float num) {return tPlan4(a/num, b/num, c/num, d/num);}
tVector3 a;
tVector3 b;
tVector3 c;
tVector3 d;
}tPlan4;
Arrays with Structs and constructors !?
It seems I went writing this same threat in the bad folder: For beginners…
So I retry my chance here if somebody could help me with a typedef struct I took from a tutorial, having thought I could add another struct containing a constructor too, to ease the operations on those packages of data…the package is not so big, but it could be it fast…
So here they are:
Pretty please, how could I retrieve a usable form from these structures to avoid any error from the compiler ?!
Which are:
error C2677: binary '*' : no global operator defined which takes type 'struct tVector3' (or there is no acceptable conversion)
all for the lines only concerning * operator in tPlan4 or tPlan2…?!
Someone somebody some spirit ?
After that most important if that somewhat is known how to declare and use arrays with that type of typedefStruct pleaseYourself !!
edit by k2: added source tags
[Edited by - kSquared on October 22, 2005 7:49:49 AM]
You haven't defined a '*' operator to take, respectively, a float then a tVector3, but you have an operator '*' defined for tVector3 that takes a float as its argument. You just need to replace all instances of "num*x" with "x*num", where x is any tVector3.
Also, if this is C++, you don't need the typedefs.
EDIT: So something like this:
Also, if this is C++, you don't need the typedefs.
EDIT: So something like this:
struct tVector3{ tVector3() {} // constructor tVector3 (float new_x, float new_y, float new_z) // initialize constructor {x = new_x; y = new_y; z = new_z;} tVector3 operator+(tVector3 vVector) {return tVector3(vVector.x+x, vVector.y+y, vVector.z+z);} tVector3 operator-(tVector3 vVector) {return tVector3(x-vVector.x, y-vVector.y, z-vVector.z);} tVector3 operator*(float number) {return tVector3(x*number, y*number, z*number);} tVector3 operator/(float number) {return tVector3(x/number, y/number, z/number);} float x, y, z;};struct tPlan2{ tPlan2() {} tPlan2(tVector3 new_a, tVector3 new_b) {a= new_a; b=new_b;} tPlan2 operator+(tPlan2 vPlan) {return tPlan2(vPlan.a+a, vPlan.b+b);} tPlan2 operator-(tPlan2 vPlan) {return tPlan2(a-vPlan.a, b-vPlan.b);} tPlan2 operator*(float num) {return tPlan2(a*num, b*num);} tPlan2 operator/(float num) {return tPlan2(a/num, b/num);} tVector3 a; tVector3 b;};struct tPlan4{ tPlan4() {} tPlan4(tVector3 new_a, tVector3 new_b, tVector3 new_c, tVector3 new_d) {a=new_a; b=new_b; c=new_c; d=new_d;} tPlan4 operator+(tPlan4 vPlan) {return tPlan4(vPlan.a+a, vPlan.b+b, vPlan.c+c, vPlan.d+d);} tPlan4 operator-(tPlan4 vPlan) {return tPlan4(vPlan.a-a, vPlan.b-b, vPlan.c-c, vPlan.d-d);} tPlan4 operator*(float num) {return tPlan4(a*num, b*num, c*num, d*num);} tPlan4 operator/(float num) {return tPlan4(a/num, b/num, c/num, d/num);} tVector3 a; tVector3 b; tVector3 c; tVector3 d;};
More generally, so that you do not fall foul of this problem when you use operator* in other code, you should implement a non-member operator* which takes a first parameter of type float and a second parameter of type tPlan2 or tPlan4 as appropriate.
Additionally, you should add const qualification to your operators and I would advise making the existing versions non member as well, since there is no need for them to be members:
It may also be an idea to implement operator+=, operator-=, operator*= and operator/= and implement your current operators in terms of those, i.e.:
Enigma
Additionally, you should add const qualification to your operators and I would advise making the existing versions non member as well, since there is no need for them to be members:
struct Vector3{ Vector3() { } Vector3(float new_x, float new_y, float new_z) : x(new_x), y(new_y), z(new_z) { } float x, y, z;};Vector3 operator+(Vector3 const & lhs, Vector3 const & rhs){ return Vector3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);}Vector3 operator-(Vector3 const & lhs, Vector3 const & rhs){ return Vector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z);}Vector3 operator*(Vector3 const & vector, float multiplier){ return Vector3(vector.x * multiplier, vector.y * multiplier, vector.z * multiplier);}Vector3 operator*(float multiplier, Vector3 const & vector){ return vector * multiplier;}Vector3 operator/(Vector3 const & vector, float divisor){ return Vector3(vector.x / divisor, vector.y / divisor, vector.z / divisor);}struct Plan2 // Plane2 or PlanePointNormal?{ Plan2() { } Plan2(Vector3 new_a, Vector3 new_b) // use better names : a(new_a), b(new_b) { } Vector3 a; Vector3 b;};Plan2 operator+(Plan2 const & lhs, Plan2 const & rhs){ return Plan2(lhs.a + rhs.a, lhs.b + rhs.b);}Plan2 operator-(Plan2 const & lhs, Plan2 const & rhs){ return Plan2(lhs.a - rhs.a, lhs.b - rhs.b);}Plan2 operator*(Plan2 const & plan, float multiplier){ return Plan2(plan.a * multiplier, plan.b * multiplier);}Plan2 operator*(float multiplier, Plan2 const & plan){ return plan * multiplier;}Plan2 operator/(Plan2 const & plan, float divisor){ return Plan2(plan.a / divisor, plan.b / divisor);}struct Plan3 // Plane3 or PlaneCartesian?{ Plan3() { } Plan3(Vector3 new_a, Vector3 new_b, Vector3 new_c, Vector3 new_d) // use better names : a(new_a), b(new_b), c(new_c), d(new_d) { } Vector3 a; Vector3 b; Vector3 c; Vector3 d;};Plan3 operator+(Plan3 const & lhs, Plan3 const & rhs){ return Plan3(lhs.a + rhs.a, lhs.b + rhs.b, lhs.c + rhs.c, lhs.d + rhs.d);}Plan3 operator-(Plan3 const & lhs, Plan3 const & rhs){ return Plan3(lhs.a - rhs.a, lhs.b - rhs.b, lhs.c - rhs.c, lhs.d - rhs.d);}Plan3 operator*(Plan3 const & plan, float multiplier){ return Plan3(plan.a * multiplier, plan.b * multiplier, plan.c * multiplier, plan.d * multiplier);}Plan3 operator*(float multiplier, Plan3 const & plan){ return plan * multiplier;}Plan3 operator/(Plan3 const & plan, float divisor){ return Plan3(plan.a / divisor, plan.b / divisor, plan.c / divisor, plan.d / divisor);}
It may also be an idea to implement operator+=, operator-=, operator*= and operator/= and implement your current operators in terms of those, i.e.:
Vector3 & operator+=(Vector3 & lhs, Vector3 const & rhs){ lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z; return lhs;}Vector3 operator+(Vector3 lhs, Vector3 const & rhs){ return lhs += rhs;}
Enigma
Mostly consistency, but also (a very small part) future-proofing.
Consistency for two reasons. First, operatorX(Non-ClassInstance, ClassInstance) must be a non-member and therefore for consistency the other operators should be non-members as well. Secondly any class that has an implicit type conversion from X (i.e. any class with a non-explicit constructor taking at least one parameter for which all or all but the first parameter have default values) will need to have non-member operators in order to gain type conversion of the left hand object:
Since classes which require implicit type conversion on the left hand object must have non-member operators all classes should have non-member operators for consistency.
Finally, the future proofing leads on from the last point. If the class were ever to gain a type conversion from X then it's operators will need to be non-members. There is obviously less maintenance to do if the operators are already non-members.
Enigma
Consistency for two reasons. First, operatorX(Non-ClassInstance, ClassInstance) must be a non-member and therefore for consistency the other operators should be non-members as well. Secondly any class that has an implicit type conversion from X (i.e. any class with a non-explicit constructor taking at least one parameter for which all or all but the first parameter have default values) will need to have non-member operators in order to gain type conversion of the left hand object:
struct OtherType{};struct Type{ Type(); Type(OtherType const & ot); Type operator+(Type const & t) const; // member operator};Type operator-(Type const & lhs, Type const & rhs); // non-member operatorint main(){ Type t1; OtherType ot1; Type t2 = t1 + ot1; // fine - type conversion on parameter Type t3 = ot1 + t1; // error - no type conversion possible on "this" Type t4 = t1 - ot1; // fine - type conversion on second parameter Type t5 = ot1 - t1; // fine - type conversion on first parameter}
Since classes which require implicit type conversion on the left hand object must have non-member operators all classes should have non-member operators for consistency.
Finally, the future proofing leads on from the last point. If the class were ever to gain a type conversion from X then it's operators will need to be non-members. There is obviously less maintenance to do if the operators are already non-members.
Enigma
Everything went super well! For sure it was a sure thing ;-) It works as on wheels, but as the truncated f numbers that dig you intervals of mistakes, the unknown of those quadric parentheses welcomes the times of “arrays uses” seeking and tries…with that kind of structure.
I thought about something like this :
To be continued...
I thought about something like this :
struct zen{The wind flies, the water wets, the fire burns;…No idea of how;}
To be continued...
Quote:Original post by Enigma, ClassInstance) must be a non-member and therefore for consistency the other operators should be non-members as well. Secondly any class that has an implicit type conversion from X (i.e. any class with a non-explicit constructor taking at least one parameter for which all or all but the first parameter have default values) will need to have non-member operators in order to gain type conversion of the left hand object:
Mostly consistency, but also (a very small part) future-proofing.
Consistency for two reasons. First, operatorX(Non-ClassInstance
*** Source Snippet Removed ***
Since classes which require implicit type conversion on the left hand object must have non-member operators all classes should have non-member operators for consistency.
Finally, the future proofing leads on from the last point. If the class were ever to gain a type conversion from X then it's operators will need to be non-members. There is obviously less maintenance to do if the operators are already non-members.
Enigma
I see, but why does hardly anyone make those operators non member?
Even in 99 C++ gotchas they make operators members of the class which sounds seems logical to me, because you encapsulate the implementation into the type which makes maintainance a lot easier if you switch class types later on in your project
you just make sure the Class-Instance Class-Instance operators fullfil the specification and you are fine
only the none-Class-Instance operators need to be changes
You didn’t write for nothing enigma if you counted to be understood…
After revising my pointers and references I got it fine ‘bout the type conversion.
Thanks Basiror for asking ‘bout the non-member, I wouldn’t ask until the next error!
The “opened” construction of operators making possible the conversion of data between references… but as usual? I mean as a simple conversion between an integer and a float for example, following the same rules?
Conserving the required use of references and pointers I see…
After revising my pointers and references I got it fine ‘bout the type conversion.
Thanks Basiror for asking ‘bout the non-member, I wouldn’t ask until the next error!
The “opened” construction of operators making possible the conversion of data between references… but as usual? I mean as a simple conversion between an integer and a float for example, following the same rules?
Conserving the required use of references and pointers I see…
Quote:Original post by Basiror
I see, but why does hardly anyone make those operators non member?
Because Enigma's approach requires that your class/struct have public member variables, which (generally) contradicts encapsulation and data hiding. For a simple numerical type like a vector, his approach may be adequate, but not for more complex types with internal representations requiring a high degree of numerical stability. Exposing those publicly almost invites (dumber) programmers to directly access the values.
Of course, property-like accessors could ameliorate the problem somewhat.
In response to Oluseyi's point I would point out that although I didn't state so explicitly (and probably should have done) what I wrote only fully applies to operatorX and not operatorX=. Since operatorX= can never require an implicit type conversion on the left hand operand or have a left hand operand of non-class type operatorX= can safely be made a member and operatorX a non-member implemented in terms of operatorX=.
You may feel that breaks the point I was making about consistancy, but the real meat of the point is that if you always implement operatorX as a non-member it will never be a wrong choice. Equally if you always implement operatorX= as a member it will never be a wrong choice. The fact that I wrote a non-member operatorX= in my first post nonwithstanding (since that was mostly to save a few lines rather than for any deep reason).
Enigma
You may feel that breaks the point I was making about consistancy, but the real meat of the point is that if you always implement operatorX as a non-member it will never be a wrong choice. Equally if you always implement operatorX= as a member it will never be a wrong choice. The fact that I wrote a non-member operatorX= in my first post nonwithstanding (since that was mostly to save a few lines rather than for any deep reason).
Enigma
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement