|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic |
Last Thread Next Thread ![]() |
| Feedback on my vector class implementations |
|
![]() zeeli Member since: 10/30/2005 |
||||
|
|
||||
| Hi, I'd like to get some feedback on my 2d and 3d vector class implementations. Vector3.h #ifndef VECTOR3_H #define VECTOR3_H #include <cmath> template<typename T> class Vector3 { public: Vector3() : m_tX(0), m_tY(0), m_tZ(0) {} Vector3(T tX, T tY, T tZ) : m_tX(tX), m_tY(tY),m_tZ(tZ) {} Vector3(const Vector3<T> &rhs) { if(*this == rhs) { return *this; } *this = rhs; } ~Vector3() {} inline bool operator ==(const Vector3<T> &rhs) { return (m_tX == rhs.m_tX && m_tY == rhs.m_tY && m_tZ == rhs.m_tZ); } inline bool operator !=(const Vector3<T> &rhs) { return (m_tX != rhs.m_tX && m_tY != rhs.m_tY && m_tZ != rhs.m_tZ); } inline bool operator <(const Vector3<T> &rhs) { return (m_tX < rhs.m_tX && m_tY < rhs.m_tY && m_tZ < rhs.m_tZ); } inline bool operator <=(const Vector3<T> &rhs) { return (m_tX <= rhs.m_tX && m_tY <= rhs.m_tY && m_tZ <= rhs.m_tZ); } inline bool operator >(const Vector3<T> &rhs) { return (m_tX > rhs.m_tX && m_tY > rhs.m_tY && m_tZ > rhs.m_tZ); } inline bool operator >=(const Vector2<T> &rhs) { return (m_tX >= rhs.m_tX && m_tY >= rhs.m_tY && m_tZ >= rhs.m_tZ); } inline Vector2<T> &operator =(const Vector2<T> &rhs) { if(*this == rhs) { return *this; } *this = rhs; return *this; } inline Vector3<T> &operator +(const Vector3<T> &rhs) { Vector3<T> vec; vec.m_tX = m_tX + rhs.m_tX; vec.m_tY = m_tY + rhs.m_tY; vec.m_tZ = m_tZ + rhs.m_tZ; return vec; } inline Vector3<T> &operator +=(const Vector3<T> &rhs) { Vector3<T> vec; vec.m_tX = m_tX += rhs.m_tX; vec.m_tY = m_tY += rhs.m_tY; vec.m_tZ = m_tZ += rhs.m_tZ; return vec; } inline Vector3<T> &operator -(const Vector3<T> &rhs) { Vector3<T> vec; vec.m_tX = m_tX - rhs.m_tX; vec.m_tY = m_tY - rhs.m_tY; vec.m_tZ = m_tZ - rhs.m_tZ; return vec; } inline Vector3<T> &operator -=(const Vector3<T> &rhs) { Vector3<T> vec; vec.m_tX = m_tX -= rhs.m_tX; vec.m_tY = m_tY -= rhs.m_tY; vec.m_tZ = m_tZ -= rhs.m_tZ; return vec; } inline Vector3<T> &operator *(T tScalar) { Vector3<T> vec; vec.m_tX = m_tX * tScalar; vec.m_tY = m_tY * tScalar; vec.m_tZ = m_tZ * tScalar; return vec; } inline T magnitude() { return sqrt((m_tX * m_tX) + (m_tY * m_tY) + (m_tZ * m_tZ)); } inline void normalize() { T magnitude = magnitude(); m_tX = m_tX / magnitude; m_tY = m_tY / magnitude; m_tZ = m_tZ / magnitude; } inline Vector3<T> cross(const Vector3<T> &rhs) { Vector2<T> vec; vec.m_tX = (m_tY * rhs.m_tZ) - (m_tZ * rhs.m_tY); vec.m_tY = (m_tZ * rhs.m_tX) - (m_tX * rhs.m_tZ); vec.m_tZ = (m_tX * rhs.m_tY) - (m_tY * rhs.m_tX); return vec; } inline T dot(const Vector3<T> &rhs) { return (m_tX * rhs.m_tX + m_tY * rhs.m_tY + m_tZ * rhs.m_tZ); } inline T x() { return m_tX; } inline T y() { return m_tY; } inline T z() { return m_tZ; } private: T m_tX, m_tY, m_tZ; }; typedef Vector3<float> vector3f; typedef Vector3<double> vector3d; #endif //VECTOR3_H Vector2.h #ifndef VECTOR2_H #define VECTOR2_H #include <cmath> template<typename T> class Vector2 { public: Vector2() : m_tX(0), m_tY(0) {} Vector2(T tX, T tY) : m_tX(tX), m_tY(tY) {} Vector2(const Vector2<T> &rhs) { if(*this == rhs) { return *this; } *this = rhs; } ~Vector2() {} inline bool operator ==(const Vector2<T> &rhs) { return (m_tX == rhs.m_tX && m_tY == rhs.m_tY); } inline bool operator !=(const Vector2<T> &rhs) { return (m_tX != rhs.m_tX && m_tY != rhs.m_tY); } inline bool operator <(const Vector2<T> &rhs) { return (m_tX < rhs.m_tX && m_tY < rhs.m_tY); } inline bool operator <=(const Vector2<T> &rhs) { return (m_tX <= rhs.m_tX && m_tY <= rhs.m_tY); } inline bool operator >(const Vector2<T> &rhs) { return (m_tX > rhs.m_tX && m_tY > rhs.m_tY); } inline bool operator >=(const Vector2<T> &rhs) { return (m_tX >= rhs.m_tX && m_tY >= rhs.m_tY); } inline Vector2<T> &operator =(const Vector2<T> &rhs) { if(*this == rhs) { return *this; } *this = rhs; return *this; } inline Vector2<T> &operator +(const Vector2<T> &rhs) { Vector2<T> vec; vec.m_tX = m_tX + rhs.m_tX; vec.m_tY = m_tY + rhs.m_tY; return vec; } inline Vector2<T> &operator +=(const Vector2<T> &rhs) { Vector2<T> vec; vec.m_tX = m_tX += rhs.m_tX; vec.m_tY = m_tY += rhs.m_tY; return vec; } inline Vector2<T> &operator -(const Vector2<T> &rhs) { Vector2<T> vec; vec.m_tX = m_tX - rhs.m_tX; vec.m_tY = m_tY - rhs.m_tY; return vec; } inline Vector2<T> &operator -=(const Vector2<T> &rhs) { Vector2<T> vec; vec.m_tX = m_tX -= rhs.m_tX; vec.m_tY = m_tY -= rhs.m_tY; return vec; } inline Vector2<T> &operator *(T tScalar) { Vector2<T> vec; vec.m_tX = m_tX * tScalar; vec.m_tY = m_tY * tScalar; return vec; } inline T magnitude() { return sqrt((m_tX * m_tX) + (m_tY * m_tY)); } inline void normalize() { T magnitude = magnitude(); m_tX = m_tX / magnitude; m_tY = m_tY / magnitude; } inline T dot(const Vector2<T> &rhs) { return (m_tX * rhs.m_tX + m_tY * rhs.m_tY); } inline T x() { return m_tX; } inline T y() { return m_tY; } private: T m_tX, m_tY; }; #endif //VECTOR2_H Please tell me if you find any flaws or things that should be improved. Best regards, zEeLi |
||||
|
||||
![]() grekster Member since: 4/23/2004 From: Whitley Bay, United Kingdom |
||||
|
|
||||
| You have some typos in your code, some of the Vector3 methods reference Vector2. |
||||
|
||||
![]() ToohrVyk Member since: 9/12/2002 From: Paris, France |
||||
|
|
||||
| Your comparison operators are incorrect. How does (0,1) compare to (1,0) ? If you really insist on comparing vectors, use lexicographical order. You seem to be returning from a constructor, which is meaningless. You also implement your copy constructor in terms of the assignment operator. The end result is that your copy constructor is both longer and slower than the default, compiler-provided copy constructor. Even worse, you implement your assignment operator in terms of itself! And it's not exception-safe! Perhaps you should compile and use your class before asking for feedback, so that you don't publish code that just doesn't work? Blog — Facebook |
||||
|
||||
![]() zeeli Member since: 10/30/2005 |
||||
|
|
||||
| Thank you both. |
||||
|
||||
![]() rozz666 Member since: 5/27/2007 From: Lodz, Poland |
||||
|
|
||||
What's THAT?!Vector3(const Vector3<T> &rhs) { if(*this == rhs) { return *this; } *this = rhs; } Constructors don't return anything. Vector3(const Vector3<T>& rhs) : m_x(rhs.m_x), m_y(rhs.m_y), m_z(rhs.m_z) { } Provide a constructor from different vector types. Remove the empty destructor declaration, the default is already provided. Make Vector3 a struct. There's no need to ide anything. Make m_x, m_y and m_z public instead of providing accessors. The <, <=, >=, > operators don't make sense for vectors. Make all binary operators, except =, +=, etc. non-member to avoid unpleasant suprises. You've missed std:: before sqrt. In your normalize function check for magnitude == 0 or near 0. Make cross, dot, normalize etc. non-member. The same applies for Vector2. Edit: The default constructor already provides what's needed. |
||||
|
||||
![]() zeeli Member since: 10/30/2005 |
||||
|
|
||||
Quote: What would those be? |
||||
|
||||
![]() rozz666 Member since: 5/27/2007 From: Lodz, Poland |
||||
|
|
||||
Quote: Vector3<int> a; Vector3<float> b; Vector3<float> c; c = a + b; What's the type of a + b? If + is a member function, it's Vector3<int>. You have to ways to handle this. 1) Implement type promotion for your vectors. 2) Make + non-member. a + b would fail to compile. |
||||
|
||||
![]() rozz666 Member since: 5/27/2007 From: Lodz, Poland |
||||
|
|
||||
| The other problem may be: Vector3<float> a(1.5, 1.5, 1.5); Vector3<int> b(1, 1, 1); a == b -> false b == a -> true |
||||
|
||||
![]() rozz666 Member since: 5/27/2007 From: Lodz, Poland |
||||
|
|
||||
| Some reading... |
||||
|
||||
![]() jyk GDNet+ Member since: 10/23/2003 |
||||
|
|
||||
Quote:That isn't necessarily true (IMO). The < operator (implemented as a lexicographical comparison) can be useful for storing vectors in associative containers, among other things. Quote:@The OP: Making the member data public is a valid choice, but be aware that it's not the only 'right way' to do it - keeping the data private is valid as well. (I did notice though that you don't provide any way to set the values of individual elements.) Here are a few more observations (some of these may have already been pointed out): 1. It looks like some of your assignment operators (e.g. +=) return a reference to a temporary. What you want is return *this. 2. You'll probably want a 'squared length' function as well as 'length'. Implement the squared length function as return dot(*this, *this), and the length (or magnitude) function as return std::sqrt(squared_length()); this will reduce code duplication. 3. Your != conditional should use the logical operator ||, not &&. 4. Expressions of the form scalar * vector are not currently possible. You'll need to add a binary non-member operator to fix this (and, as has already been mentioned, the other binary operators in your classes should really be made non-member as well). 5. Functions defined within the class body are implicitly marked inline, so you don't need the inline keyword. 6. What's the 't' in (e.g.) m_tX for? [ Configurable Math Library ] |
||||
|
||||
![]() zeeli Member since: 10/30/2005 |
||||
|
|
||||
Quote: Thank you for your time mate! The t is for variable type T |
||||
|
||||
![]() jyk GDNet+ Member since: 10/23/2003 |
||||
|
|
||||
Quote:I suggest dropping the 't', as it just clutters up the code without adding any useful information (IMO). For further arguments for and against this type of notation, Google or search the forum archives for 'hungarian notation'. |
||||
|
||||
All times are ET (US)![]() |
Last Thread Next Thread ![]() |
|