The const operator

Started by
15 comments, last by Doc 19 years, 1 month ago
Hi everybody, If I compile the following programm:

class vector
{
public:
  float x,y;
  inline float dot(const vector other)
  {return x*other.x+y*other.y;}
};

void func(const vector a,const vector b)
{
  float x=a.dot(b);
}

int main()
{
  return 0;
}



I get the following error from g++: test2.cc: In function `void func(vector, vector)': test2.cc:12: error: passing `const vector' as `this' argument of `float vector::dot(vector)' discards qualifiers But if I replace

void func(const vector a,const vector b)
{
  float x=a.dot(b);
}



with

void func(const vector a,const vector b)
{
  float x=a.x*b.x+a.y*b.y;
}


Everything works! I do not understand. What is the problem, why would that not work? Must admit, I also do not understand the g++ error message. Thanks! Nathan
Advertisement
inline float dot(const vector other)

should be
inline float dot(const vector other) const


a member function that does not alter the internal state of the object should be marked const
Actually, it should really be inline float dot(const vector& other) const.

Pass by const-reference is your friend.

I also like binary-operator-like functions like dot to be non-member functions - to the point of making them friend if I have to. I like the look of dot(a,b) much better than a.dot(b).

inline float dot(const vector& lhs, const vector& rhs){  return lhs.x*rhs.x+lhs.y*rhs.y;}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
I understand ...
Thanks a lot!
Quote:Original post by Fruny
I like the look of dot(a,b) much better than a.dot(b).

inline float dot(const vector& lhs, const vector& rhs){  return lhs.x*rhs.x+lhs.y*rhs.y;}

Expanding on that a little, not only does it look better, but it also promotes symmetry in terms of conversion as well. In the first version (with the member function) only the single member function parameter can come from another object being implictly converted, while in the second version, either parameter can come from an implicit conversion. So in the member function version, if you need to have an impicit conversion on the left you'd have to explicitly cast the object, whereas in the second version that is not the case.

This is usually more important when you are doing operator overloading with a symmetric binary operator, since the syntax for calling is the same for member and non-member functions in that case can be the same. On that note, I recommend having dot product use overloaded *, although it is [almost] entirely subjective. Many people avoid operator overloading binary operator * with mathematical vectors for fear of confusion with cross product.

Also, for future reference, const is not an operator, it is a qualifier.
Quote:Original post by Polymorphic OOP
Quote:Original post by Fruny
I like the look of dot(a,b) much better than a.dot(b).

inline float dot(const vector& lhs, const vector& rhs){  return lhs.x*rhs.x+lhs.y*rhs.y;}

This is usually more important when you are doing operator overloading with a symmetric binary operator, since the syntax for calling is the same for member and non-member functions in that case can be the same. On that note, I recommend having dot product use overloaded *, although it is [almost] entirely subjective. Many people avoid operator overloading binary operator * with mathematical vectors for fear of confusion with cross product.

Also, for future reference, const is not an operator, it is a qualifier.


Using operator* for a dot product is very obfuscated. It makes for unreadable code.

vec1 * vec2 * vec3 * vec4;


Is it obvious what that code does? One dot product, followed by one multiplication followed by another dot product. Surely the operator should only be used for one thing, and that thing should be multiplication.
Quote:Original post by RigidBody
Surely the operator should only be used for one thing, and that thing should be multiplication.

Because in the minds of many mathematicians, dot product is the vector equivalent of multiplication extended into multiple dimensions. When written down on paper, dot product is even sometimes represented in the same manner as regular multiplication -- it isn't a new practice to C++ operator overloading. Convention, however, is not the reason that I prefer to use operator*.

Before going into exactly why I believe multiplication is an application of dot product, observe some of the likenesses -- in terms of math, dot-product is commutative, distributive, associative, and it has several common logical operations which parallel those of multiplication of scalars, such as, most-notably, the fact that the dot product is the multiplication of the signed magnitudes of the vectors when projected along one of their associated lines and the related fact that a vector dot-producted by itself gives you the square of its magnitude.

All of these properties hold true for multiplication of scalars. The difference is that some people think of multiplication as a scalar operation not extending to other dimensions, whereas others think of scalar multiplication as the equivalent of the dot-product in 1-dimensional space (which it actually rationally is). Take, for example, generalizing projections into 1-dimensional space, aka the number line. The projection of a scalar value, rationalized as a vector in 1-dimension, onto the number line is always itself, since the vector and the number line are always going to be colinear to begin with. The magnitude of a componentized vector in 1-dimensional space, is of course, just it's own value (pythagorean in 1-dimension -- sqrt( v.x^2 )). In turn, the dot product of two scalar values is the multiplication of their signed magnitudes when one is projected onto the other, which in 1-dimensional space is just their values multiplied together. This is equivalent the simple multiplication that we know today, only now it is applicable to any number of dimensions as the dot product (inner product). The fact that the dot product of two vectors always gives you a scalar is just a generalization that is easily unnoticeable when working in 1-dimension with the number line, since 1-dimensional vectors always have just one dimensional component anyway.

So, while some people claim that multiplication of scalars and the dot-product are completely different, since multiplication of scalars yields you an object having the same type as the operands, others will acknowledge the fact that multiplication of scalars is just the dot-product of two vectors applied to vectors in 1-dimension. When you look at multiplication as the latter, it is obvious that the dot-product and multiplication should be represented in the same manner and it makes perfectly logical sense that you can (and, in my opinion should) represent them with the same operator. Since the operations can be generalized the same way, they can in turn be used in generic programming with templates the same way, since using operator* as a generalization of the dot product can apply to multiplication as well without problem.

Aside from that, it makes much more logical sense to use operator * for multiplication than it would, for example, to have the addition operator concatenate strings or the left shift operator to output text to a stream, although I personally will not argue against either one. If you argue against operator* for dot product since it's not multiplication, I'd expect you to have even bigger gripes with the latter two examples.

I don't expect to change your opinion, neither do I want to, as it is mostly subjective unless you wish to take advantage of the generalizations I've mentioned. You should, however, know that overloading operator* for dot-product is not as obscure as you might think.

[Edited by - Polymorphic OOP on March 4, 2005 4:34:18 AM]
Quote:Original post by Polymorphic OOP
page-o-stuff


Rate++. Yay math philosophy!
My stuff.Shameless promotion: FreePop: The GPL god-sim.
Quote:Original post by Doc
Quote:Original post by Polymorphic OOP
page-o-stuff


Rate++. Yay math philosophy!
Same here, one quarter of that was more than enough to convince me. I'm sold!
I only wish I could rate Poly even higher.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
Quote:Original post by Polymorphic OOP
Quote:Original post by RigidBody
Surely the operator should only be used for one thing, and that thing should be multiplication.

Because in the minds of many mathematicians, dot product is the vector equivalent of multiplication extended into multiple dimensions. When written down on paper, dot product is even sometimes represented in the same manner as regular multiplication -- it isn't a new practice to C++ operator overloading. Convention, however, is not the reason that I prefer to use operator*.

Before going into exactly why I believe multiplication is an application of dot product, observe some of the likenesses -- in terms of math, dot-product is commutative, distributive, associative, and it has several common logical operations which parallel those of multiplication of scalars, such as, most-notably, the fact that the dot product is the multiplication of the magnitudes of the vectors when projected along one of their associated lines and the related fact that a vector dot-producted by itself gives you the square of its magnitude.

All of these properties hold true for multiplication of scalars. The difference is that some people think of multiplication as a scalar operation not extending to other dimensions, whereas others think of scalar multiplication as the equivalent of the dot-product in 1-dimensional space (which it actually rationally is). Take, for example, generalizing projections into 1-dimensional space, aka the number line. The projection of a scalar value, rationalized as a vector in 1-dimension, onto the number line is always its own magnitude, since the vector and the number line are always going to be colinear to begin with. The magnitude of a componentized vector in 1-dimensional space, is of course, just it's own value (pythagorean in 1-dimension -- sqrt( v.x^2 )). In turn, the dot product of two scalar values is the multiplication of their magnitudes when one is projected onto the other, which in 1-dimensional space is just their values multiplied together. This is, of course, just the simple multiplication that we know today, only now it is applicable to any number of dimensions as the dot product. The fact that the dot product of two vectors always gives you a scalar is just a generalization that is easily unnoticeable when working in 1-dimension with the number line, since 1-dimensional vectors always have just one dimensional component anyway.

So, while some people claim that multiplication of scalars and the dot-product are completely different, since multiplication of scalars yields you an object having the same type as the operands, others will acknowledge the fact that multiplication of scalars is just the dot-product of two vectors applied to vectors in 1-dimension. When you look at multiplication as the latter, it is obvious that the dot-product and multiplication should be represented in the same manner and it makes perfectly logical sense that you can (and, in my opinion should) represent them with the same operator. Since the operations can be generalized the same way, they can in turn be used in generic programming with templates the same way, since using operator* as a generalization of the dot product can apply to multiplication as well without problem.

Aside from that, it makes much more logical sense to use operator * for multiplication than it would, for example, to have the addition operator concatenate strings or the left shift operator to output text to a stream, although I personally will not argue against either one. If you argue against operator* for dot product since it's not multiplication, I'd expect you to have even bigger gripes with the latter two examples.

I don't expect to change your opinion, neither do I want to, as it is mostly subjective unless you wish to take advantage of the generalizations I've mentioned. You should, however, know that overloading operator* for dot-product is not as obscure as you might think.


You cannot multiply two vectors, you can multiply a vector and a transpose of a vector.

vector * transpose(vector);// makes more sensevector * vector; //makes little sensedot(vector, vector); //readable

This topic is closed to new replies.

Advertisement