stylin: Yes, you're almost certainly right regards constness or return values from arithmetic operators for a simple vector. I only brought the point up because a) your advice sounded more general than that and b) having written that long post I'd forgotten what the specific case that had triggered the discussion was!
ninmonkeys:
Quote:Original post by ninmonkeys
Quote:Original post by stylin
For objects that can be used in arithmetic operations - such as your vector class - prefer to imitate the behaviour of built-in types. Create free-function operator overloads, especially if you require mixed-mode arithmetic - multiplying a vector by a scalar, for example.
What is the reason to declare all the overloaded operators as free functions? I'm wondering since it sounds like enigma said to do it another way. (Assuming I understand enigma right: create operatorX=() as members, and the rest of the operatorX()'s as free functions that use the operatorX=() operators)
I said
in general to make operator
X=() a member function. Unfortunately I forgot to mention the main exception to this advice, which is if you can trivially make it a free function then you may want to do so. You can trivially make operator
X=() a free function if there are no private or protected data members in the classes interface that will require operating on, i.e.:
struct TrivialVector{ // all members are public so operator+= can trivially be made a free // function. float x, y, z;};TrivialVector & operator+=(TrivialVector & lhs, TrivialVector const & rhs){ lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z;}class NormalisedVector{ public: // member functions private: // data members are now private since we must maintain an // invariant over them (x² + y² + z² == 1). // operator+= cannot trivially be made a free function - to do // so would require either declaring it a friend or implementing // it in terms of another member function. float x, y, z;};
Some people may disagree and prefer to always make operator
X=() a free function and make it a friend when neccessary. I personally prefer to avoid unneccessary friendships and always make operator
X=() a member function for consistency. This is mostly an issue of personal preference though.
Quote:Quote:Original post by stylin
In regards to constness, return by const value from arithmtic operators (+, *, etc.) to imitate the built-in types - this prevents accidental assignments to temporary objects created from these operators.
Could you give me an example of how you could have an accidental assignment of a temperary object?
Currently none of my arithmetic operators return a constant value, since I'm still figuring out if something like this would be of any use: v1 = (v2+v3).Normalize(); will be of any use or not.
In that example Normalize ought to be a const member function, so returning a const value would still allow such a construction to work, as stylin pointed out.
Quote:Quote:Original post by: Enigma
2) Generally for parameters you should use const references by default with the exception of builtin types and small classes, which should be passed by value, objects which need to be modified by the function, which should be passed by non-const reference, and objects which might not exist, which should be passed by pointer (with or without const depending on whether or not they need to be modified).
Why pass a small class by value? (I thought pointers were always faster to pass than by value?)
It will be no slower to pass a small value than a pointer and passing by value eliminates a dereference on access and improves locality of data. It's a minor point and not worth spending too much time over. Pick reasonable defaults and if a profiler eventually demonstrates that you made the wrong choice it should be trivial to change it.
Quote:Quote:Original post by: Enigma
3. operatorX() may either be a member function or a free function. If it is a member then it takes one parameter and this acts as the other parameter. If it is a free function then it takes two parameters. Generally prefer to make operatorX() a free function implemented in terms of the member function operatorX=():
Does that mean make operatorX=() functions members, and the rest as free functions? What is the reasoning for this?
It means you only implement the operator in one place, so any maintenance only has to be done in one place. For example imagine you have a three component (x, y & z) vector class with operator+ and operator+=() both independantly implemented. If you decide to change your vector to four components (x, y, z & w) then you must rewrite
two operators. By implementing operator+() in terms of operator+= you only have to update
one operator. It may seem like a small saving, but when you start overloading more operators in more complex classes the work saved soon adds up. Membership has already been discussed.
Quote:The possible reason I ran into was right now all of mine are member functions, and I could declare "vecor * scalar" but not "scalar * vector". Which I'm not sure if it is my fault, or that it has to be a free function to declare both?
It has to be a free function to gain implicit type conversion on both arguments. C++ will implicitly convert types in parameter lists if it can, but will never implicitly convert an object so that it can call a member function on it. So in order to get implicit type conversion on the left hand argument you must implement the operator as a free function. Note that operator
X=() never requires type conversion on its left hand argument.
Enigma