• Advertisement

Archived

This topic is now archived and is closed to further replies.

a vector class

This topic is 5268 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

i want to make a vector class and was curious about a few things: The way the vector class was made on NeHe site (code below) uses operator overloading for basic functions between the vectors, where other places i have seen a simple class or struct used to represent a vector with just x, y, z, w values in it and then seperate functions to add, multiply, crossprduct etc. are there any advantages or disadvantages to each of these methods? are operator overloading slow?
class VECTOR3D
{
	public:
		GLfloat vertex[3];

	float ComputeLength(void);

	friend VECTOR3D operator+ (VECTOR3D v1, VECTOR3D v2);
	friend VECTOR3D operator- (VECTOR3D v1, VECTOR3D v2);
	friend VECTOR3D operator* (VECTOR3D v1, GLfloat scalar);
	friend VECTOR3D operator* (VECTOR3D v1, VECTOR3D v2);
	friend VECTOR3D operator/ (VECTOR3D v1, VECTOR3D v2);

	VECTOR3D()
		{	memset(vertex, 0, sizeof(GLfloat[3]));	}
	VECTOR3D(GLfloat x, GLfloat y, GLfloat z);
};
Secondly: see how in the above class it uses an array to store the x, y, z values...what are the differences between using an array as opposed to having a seperate float for each value? Im thinking these things just come down to personal preferences and what u feel comfortable with, but i mite be wrong, and am curious if there are differences.

Share this post


Link to post
Share on other sites
Advertisement
I''d favour operator overloading personally, it gives you a more common feel with the rest of c++, and if you want to use things such as std::vector, you need to have some of the operators overloaded.

I''d say that having a single array of float or 3 seperate floats is preference.

Bp

Share this post


Link to post
Share on other sites
quote:

i want to make a vector class and was curious about a few things:
The way the vector class was made on NeHe site (code below) uses operator overloading for basic functions between the vectors, where other places i have seen a simple class or struct used to represent a vector with just x, y, z, w values in it and then seperate functions to add, multiply, crossprduct etc. are there any advantages or disadvantages to each of these methods? are operator overloading slow?



I have read that using operator overloading is slower, but I don't know if that still holds true with the newer computers out. You can use them them both operator overloading and regular functions.

Heres an example: (Ignore the X* stuff, I just pulled it from my engine)

class XVECTOR3
{
public:
XVECTOR3(Xvoid);
XVECTOR3(const Xfloat);
XVECTOR3(const Xfloat *);
XVECTOR3(const XVECTOR3 &);
XVECTOR3(Xfloat, Xfloat, Xfloat);

Xfloat X;
Xfloat Y;
Xfloat Z;

public:
operator Xfloat* (Xvoid);
operator const Xfloat* (Xvoid) const;

XVECTOR3 operator * (const XVECTOR3 &) const;
XVECTOR3 operator / (const XVECTOR3 &) const;
XVECTOR3 operator ^ (const XVECTOR3 &) const;
XVECTOR3 operator < (const XVECTOR3 &) const;
XVECTOR3 operator > (const XVECTOR3 &) const;
XVECTOR3 operator + (const XVECTOR3 &) const;
XVECTOR3 operator - (const XVECTOR3 &) const;
Xbool operator == (const XVECTOR3 &) const;
Xbool operator != (const XVECTOR3 &) const;
Xfloat operator % (const XVECTOR3 &) const;
XVECTOR3& operator += (const XVECTOR3 &);
XVECTOR3& operator -= (const XVECTOR3 &);
XVECTOR3& operator *= (Xfloat);
XVECTOR3& operator /= (Xfloat);
XVECTOR3 operator * (Xfloat)const;
XVECTOR3 operator / (Xfloat)const;
XVECTOR3 operator + (Xvoid) const;
XVECTOR3 operator - (Xvoid) const;

public:
XVECTOR3 Add(const XVECTOR3 *, const XVECTOR3 *);
XVECTOR3 Subtract(const XVECTOR3 *, const XVECTOR3 *);
XVECTOR3 Average(const XVECTOR3 *, const XVECTOR3 *);
XVECTOR3 Divide(Xfloat, const XVECTOR3 *);
XVECTOR3 Divide(const XVECTOR3 *, Xfloat);
XVECTOR3 Divide(const XVECTOR3 *, const XVECTOR3 *);
XVECTOR3 Multiply(Xfloat, const XVECTOR3 *);
XVECTOR3 Multiply(const XVECTOR3 *, Xfloat);
XVECTOR3 Multiply(const XVECTOR3 *, const XVECTOR3 *);
Xfloat DotProduct(const XVECTOR3 *);
Xvoid Copy(XVECTOR3 *);
Xvoid Zero(Xvoid);
Xbool IsZero(Xvoid);
Xvoid Negate(Xvoid);
Xfloat Magnitude(Xvoid);
Xfloat MagnitudeSQ(Xvoid);
Xvoid Normalize(Xvoid);
Xvoid NormalizeEX(Xvoid);
Xint Sign(Xvoid);
Xvoid CrossProduct(const XVECTOR3 *, const XVECTOR3 *);
Xvoid CrossProductEX(const XVECTOR3 *, const XVECTOR3 *);
Xfloat ScalarProduct(const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *);
Xvoid Power(const XVECTOR3 *, const XVECTOR3 *);
Xvoid Spherical(Xfloat, Xfloat, Xfloat);
Xvoid Scale(XVECTOR3 *, const XVECTOR3 *, Xfloat);
Xvoid Minimize(const XVECTOR3 *, const XVECTOR3 *);
Xvoid Maximize(const XVECTOR3 *, const XVECTOR3 *);
Xfloat Distance(const XVECTOR3 *);
Xfloat DistanceEX(const XVECTOR3 *, const XVECTOR3 *);
Xint FastDistance(Xint, Xint);
Xbool NearlyEqual(const XVECTOR3 *);
Xvoid InterpLinear(XVECTOR3 *, Xfloat, const XVECTOR3 *, const XVECTOR3 *);
Xvoid InterpHermitSpline(XVECTOR3 *, Xfloat, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *);
Xvoid InterpBSpline(XVECTOR3 *, Xfloat, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *);
Xvoid InterpBSplineT(XVECTOR3 *, Xfloat, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *);
Xvoid InterpCatmulRom(XVECTOR3 *, Xfloat, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *);
Xvoid InterpCatmulRomT(XVECTOR3 *, Xfloat, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *, const XVECTOR3 *);
};

I hardly ever use the Add, Subtract, etc. It's easier just to use V1 + V2;

quote:

Secondly: see how in the above class it uses an array to store the x, y, z values...what are the differences between using an array as opposed to having a seperate float for each value?



Nothing because you can use an array with "seperate" floats. Heres what I mean:

//--In the class you would have X, Y, and Z.

//--

//--In class

//--

float &operator[](unsigned int ID);
const float &operator [] (unsigned int ID) const;
//--

//--In .cpp (Or where ever)

//--

float &operator[](unsigned int ID)
{
return *(&X + ID);
}
//

const float &operator [] (unsigned int ID) const
{
return *(&X + ID);
}

Then you can access the values like a normal array.
Vector.X would now be the same as Vector[0].

-UltimaX-

"You wished for a white christmas... Now go shovel your wishes!"

[edited by - UltimaX on August 19, 2003 8:47:16 AM]

Share this post


Link to post
Share on other sites
If you are asking questions like this, you might want to learn more about classes.

Also note that the operators should have constant reference parameters:    

friend VECTOR3D operator+(const VECTOR3D& v1, const VECTOR3D& v2);


[ Google || Start Here || ACCU || STL || Boost || MSDN || GotW || MSVC++ Library Fixes || BarrysWorld || E-Mail Me ]

Share this post


Link to post
Share on other sites
quote:

The way the vector class was made on NeHe site (code below) uses operator overloading for basic functions between the vectors, where other places i have seen a simple class or struct used to represent a vector with just x, y, z, w values in it and then seperate functions to add, multiply, crossprduct etc. are there any advantages or disadvantages to each of these methods? are operator overloading slow?


Operator overloading can be slower than functions. That is because of the way the compiler produces the ASM code. With operator overloading, the ASM needs to make some temporary storage space to hold the result''s values before passing the it to another variable. When you use functions you can pass everything by reference and thus no temp storage is created. This can speed you up.

Personally I use both methods. I use the functions where I need the most speed. I use the operators in complicated calculations because they''re easier to read (and thus to debug).
quote:

Secondly: see how in the above class it uses an array to store the x, y, z values...what are the differences between using an array as opposed to having a seperate float for each value?


I use both by using unions. Here''s how:

union float3
{
struct
{
union {float x; float r; float t};
union {float y; float g; float u};
union {float z; float b; float v};
}
float v[3];
}

And I have overloaded the [] operator to point to v[] so I can acces my vector like:

float3 myVec;
//as array
myVec[0]=1.0f; myVec[1]=2.0f; myVec[2]=3.0f;
//as position vector
myVec.x=1.0f; myVec.y=2.0f; myVec.z=3.0f;
//as color
myVec.r=1.0f; myVec.g=2.0f; myVec.b=3.0f;
//as texture coords
myVec.t=1.0f; myVec.u=2.0f; myVec.v=3.0f;


Sander Maréchal
[Lone Wolves Game Development][RoboBlast][Articles][GD Emporium][Webdesign][E-mail]


GSACP: GameDev Society Against Crap Posting
To join: Put these lines in your signature and don''t post crap!

Share this post


Link to post
Share on other sites
quote:
Original post by UltimaX
Nothing because you can use an array with "seperate" floats. Heres what I mean:

//--In the class you would have X, Y, and Z.
//--
//--In class
//--
float &operator[](unsigned int ID);
const float &operator [] (unsigned int ID) const;
//--
//--In .cpp (Or where ever)
//--
float &operator[](unsigned int ID)
{
return *(&X + ID);
}
//
const float &operator [] (unsigned int ID) const
{
return *(&X + ID);
}
[/source]
Then you can access the values like a normal array.
Vector.X would now be the same as Vector[0].


Sorry, but this is non-portable code. The standard doesn''t state that the storage for class data members is guaranteed to be contiguous, and there are other important issues (padding, etc.).
quote:
Original post by Sander
Operator overloading can be slower than functions. That is because of the way the compiler produces the ASM code. With operator overloading, the ASM needs to make some temporary storage space to hold the result''s values before passing the it to another variable. When you use functions you can pass everything by reference and thus no temp storage is created. This can speed you up.


An overloaded operator will be exactly the same as a normal member function. I think that what you are talking about is the return value, but this is the same for both. Anyway, for this (I think) there is something called return value optimisation. For example, with an addition operator like this:

T operator+( const T& lhs, const T& rhs );

the compiler should be able to recognise this and rewrite the function internally to this:

void operator+( T& result, const T& lhs, const T& rhs );

and directly compute into result. The function call is also internally transformed. For example, this:

T a, b, c;
a = b + c;

becomes transformed internally to this:

operator+(a, b, c);

It is not widely implemented, and there are side effects, though.

Just use the compound assignment operators, i.e. +=, -=, %=, >>=, etc.

[ Google || Start Here || ACCU || STL || Boost || MSDN || GotW || MSVC++ Library Fixes || BarrysWorld || E-Mail Me ]

Share this post


Link to post
Share on other sites
quote:

Operator overloading can be slower than functions. That is because of the way the compiler produces the ASM code. With operator overloading, the ASM needs to make some temporary storage space to hold the result's values before passing the it to another variable. When you use functions you can pass everything by reference and thus no temp storage is created. This can speed you up.



You can even pass everything by reference when you use operator overloading.


struct vec
{
float x, y, z;
vec& operator = ( const vec& v )
{
x = v.x; y = v.y; z = v.y;
return *this;
}
};



When you use an operator, the compiler actually replaces it with a function call. when you do something like v1 = v2 the compiler would exchange that for v1.operator =( v2 ); which is technically the same as doing something like v1.Copy( v2 );

[edited by - Ali F on August 19, 2003 9:47:37 AM]

Share this post


Link to post
Share on other sites
There''s one advantage about using float[] over seperate floats if you''re using OpenGL. You can make your class return a const float* to your float[] (via member function or operator overloading) and then pass your vector directly to glVertex3fv for example:

glVertex3fv(myVector.toVertex());

If you''re convenient with operator overloading you can also do the following (no idea if it''s standard or a VC++ thing again);


Vector3D
{
private:
...
float magnitude[4]; // Note: I use four for safety since OpenGL also offers glVertex4fv!!!


public:
...
operator const float* (void)const;
};

Vector3D::operator const float* (void)const
{
return (magnitude);
}

Note that magnitude is four(!) floats, to make the vector compatible with all glVertex functions (2-4fv). With this operator the compiler will be able to convert your Vector to a const float* whenever needed. You implicitly gain a [] operator, but without boundary checking!

Share this post


Link to post
Share on other sites
The advantage of a float array member is that you can provide an overloaded subscript operator for your class, whereas I wouldn''t recommend what UltimaX does (see my second post on this thread).

Wildfire: Do you realise the implications of implicit conversion operators? They are generally not worth it.

[ Google || Start Here || ACCU || STL || Boost || MSDN || GotW || MSVC++ Library Fixes || BarrysWorld || E-Mail Me ]

Share this post


Link to post
Share on other sites
quote:

Sorry, but this is non-portable code. The standard doesn't state that the storage for class data members is guaranteed to be contiguous, and there are other important issues (padding, etc.).


I don't remember saying that it was portable.

quote:

The advantage of a float array member is that you can provide an overloaded subscript operator for your class, whereas I wouldn't recommend what UltimaX does (see my second post on this thread).


Look at my vector class, do you see them 2 overloaded operators in there? NO! I don't use them, I was just showing them for an example, so why don't you just lay off a little bit!

BTW:
It's the same way the matrix library does for the Game Programming Gems series. Isn't most of that code portable? If those operators were not portable why would they put them in there?

-UltimaX-

"You wished for a white christmas... Now go shovel your wishes!"

[edited by - UltimaX on August 19, 2003 10:52:24 AM]

Share this post


Link to post
Share on other sites
quote:

Wildfire: Do you realise the implications of implicit conversion operators? They are generally not worth it.


Yes I do... they can cause a lot of trouble.

For example the compiler won't (might not) know which []-operator to use, if the class also provides one.

Actually my vector class is the only case I ever used them, without running into trouble. A member function like 'toConstFloat' is usually a better idea.

I just like being able to do
glVertex3fv(vector) instead of glVertex3fv(vector.toConstFloat())

[edited by - Wildfire on August 19, 2003 10:49:57 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by UltimaX
I don''t remember saying that it was portable.


Well, that was supposed to be a polite way of saying that it is a hack.
quote:
Original post by UltimaX
Look at my vector class, do you see them 2 overloaded operators in there? NO! I don''t use them, I was just showing them for an example, so why don''t you just lay off a little bit!


Mate, calm down. I''m merely stating, I''m not trying to be patronising, or spiteful.
quote:
Original post by UltimaX
BTW:
It''s the same way the matrix library does for the Game Programming Gems series. Isn''t most of that code portable? If those operators were not portable why would they put them in there?


The thing is that, although (AFAIK) the standard doesn''t guarantee it, many compilers implement the storage as contiguous.
quote:
Original post by Wildfire
A member function like ''toConstFloat'' is usually a better idea.


Yep, you have the right idea.

[ Google || Start Here || ACCU || STL || Boost || MSDN || GotW || MSVC++ Library Fixes || BarrysWorld || E-Mail Me ]

Share this post


Link to post
Share on other sites
thanks for all the replies people.

LekTrix, yes i think i do have to learn more about classes, and after reading the responses to this post i think i have to learn lots more about C++ in general!

also why should operators have constant refererence parameters? what is the difference?

Share this post


Link to post
Share on other sites
The main difference between passing a value and passing a reference is that a reference, like a pointer does not create a temporary copy of the object.

Let's say you've got a '+'-operator which expects another Vector.

Vector Vector::operator + (Vector add)
{...};

This way everytime you use the + your computer has to create a copy of the Vector you're passing, which is slow, because the compiler will have to call the classes constructor. As soon as the member-function is done the computer will call the classes destructor.

Vector Vector::operator + (Vector& add)
{...};

This way no copy of your Vector will be created, instead you get a reference (similar to a pointer, different syntax and can't be re-located like a pointer), which is faster. But this way you could also change the Vector you've been passed.

Vector Vector::operator + (const Vector& add)const
{...}

Same advantages like above, but this time you make it clear to the user of your class that you won't change the object passed
and that you won't even be changing your own object (notice the const at the end). Operator+ will usually return a new Vector which is the addition of both operands, and not change any of the operands.

[edited by - Wildfire on August 20, 2003 2:50:30 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Wildfire
I just like being able to do
glVertex3fv(vector) instead of glVertex3fv(vector.toConstFloat())


static inline void glVertex(const Vector& v) { glVertex3f(v.x,v.y,v.z); }

what? :D

i don't use those functions often anyways.. VBO, arrays, all the way to go.. :D

"take a look around" - limp bizkit
www.google.com

[edited by - davepermen on August 20, 2003 2:48:30 AM]

[edited by - davepermen on August 20, 2003 2:48:57 AM]

Share this post


Link to post
Share on other sites
quote:

static inline void glVertex(const Vector& v) { glVertex3f(v.x,v.y,v.z); }


Heh... nice idea. Never even crossed my mind.
On the other hand, I don''t really like it because you explicitly ''bind'' your vector to OpenGL. The vector class is pretty much universal otherwise.

Share this post


Link to post
Share on other sites
I have an implicit cast to float* for all my vectors so I can use it in almost any OpenGL function. I also overloaded the OGL functions for vertex buffers so I can use my vector type with it

glVertexPointer(1, GL_FLOAT3, 0, vertexBuffer);



Sander Maréchal
[Lone Wolves Game Development][RoboBlast][Articles][GD Emporium][Webdesign][E-mail]


GSACP: GameDev Society Against Crap Posting
To join: Put these lines in your signature and don''t post crap!

Share this post


Link to post
Share on other sites
Wildfire: thanx for the explanation on references and why u use const. that was well explained

Share this post


Link to post
Share on other sites
quote:
Original post by Wildfire
quote:

static inline void glVertex(const Vector& v) { glVertex3f(v.x,v.y,v.z); }


Heh... nice idea. Never even crossed my mind.
On the other hand, I don''t really like it because you explicitly ''bind'' your vector to OpenGL. The vector class is pretty much universal otherwise.


nope. its a free function, wich makes a tie to your vector and opengl. you can specify such things for opengl, too..

as all wgl stuff ties win32 and opengl together. still they are independend.

as sdl has an SDL_OPENGL part in to tie gl and sdl together, still, they are independend.

vector doesn''t rely on opengl.

you can put those into another header if you want.. vecgl.h or what ever :D

"take a look around" - limp bizkit
www.google.com

Share this post


Link to post
Share on other sites
quote:

nope. its a free function, wich makes a tie to your vector and opengl. you can specify such things for opengl, too..


Yes, true. But that''s not what I meant. Someone might call the member-function without having a valid OpenGL context, and bam...
Ok, that''s only theoretical, I think I''ll adopt your idea into my vector class .

Leedude: You''re welcome

quote:

I wonder what John Carmack''s Vector class looks like


Who cares... just because he''s a brilliant 3D Programmer doesn''t mean his ideas must apply to everyone and must be the best in all cases... and I think there''s just so much freedom when designing a vector class. After all a vector is a mathematical thing. The basic function is the same, no matter what you name your functions and how you represent them. Just my thoughts. No flaming please for not bowing to the god .

Share this post


Link to post
Share on other sites

  • Advertisement