Operator Overloading Question(s)

Hi,

I'm now at Operator Overloading in the tutorials I'm following.

Now it explains how to overload conversion operators, like: int varname = (int)floatvarname.

If you overload operators like + and -, the syntax is like this:
1
2
3
4
5
6
classname classname::operator-(const classname& object1)
{
  classname object2;
  *some calculations*
  return object2;
}


I understand this. But now, when overloading conversion operators, there is no return type.
class definition:
operator int();

Method:
classname::operator int()

So why use a return type when overloading operators like + and -, but no return type when overloading conversion operators? Also, though there is no return type, the return keyword is used in the example and it works. Why?
Last edited on
Because in conversion operators the return type is the one you are converting to.
EG: Would be useless having an operator which converts from classname to int but returns std::string
Hi Bazzy

Thanks for the answer.

Oh well, sometimes things are so logic that I can't think of them :$
Ah, that explains it.

The correct declaration of operator+ is:

ClassName operator+( const ClassName& rhs ) const;

Note the const at the end.

The tutorial on this site is wrong.
Why const at the end? it works fine without it. Also, I'm not using the tutorials on this site..
Last edited on
Adding const after the function prototype makes the method working also for constant object of the class
( a const method can't modify the object members unless they are declared mutable and any method which doesn't modify the members should be const )
Eg:
1
2
3
4
void func ( const ClassName &a, const ClassName &b )
{
    ClassName c = a+b; // if operator + isn't const, this won't work
} 

Last edited on
I don't get it. a and b aren't changed in the function, so why make the function constant?
Can you explain this a bit more. I've never seen a constant function. What's the use of that?

Also, it works here without it..

Btw: what does rhs stands for? Saw it different times.
Last edited on
In my example a and b are passed as const references, a const object can call only const methods so the + operator has to be const or calling a+b wouldn't be possible
a and b aren't changed in the function, so why make the function constant?


This is referred to as const-correctness.

Basically when you have const objects, you can only call const member functions because non-const member functions might potentially change the object. Even if the function does not change the object, the compiler will still bark at you because it has no way of knowing that without compiling the function (which it might not be able to do -- like say, if the function is in a separate .cpp file).

Making a member function const does 3 things:
1) it prevents your from changing any member variables in the 'this' object (the compiler will complain if you try)
2) it prevents you from calling any non-const member functions (because they might change 'this')
3) it allows the member function to be called from const objects.

To simplify it....basicaly if you have a member function that doesn't change any member vars or modify the object in any way, you want to make it a const function so that it can be used with const objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class C
{
public:
  void foo()                  // nonconst member function
  { cout << "foo\n"; }

  void bar() const            // const member function
  { cout << "bar\n"; }
};

int main()
{
  C a;
  const C b;

  a.foo();   // works fine
  a.bar();   // works fine

  b.foo();   // ERROR, b is const, can't call nonconst member function
  b.bar();   // works fine

  return 0;
}


Since overloaded operators are effectively functions -- it's the same idea.

Btw: what does rhs stands for? Saw it different times.


I think it's just "right hand side", as in it's the parameter on the right hand side of the operator.
Last edited on
I'm starting to understand it =)

But not fully yet :(

Let's assume I have this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class C
{
public:
  void foo()                  
  { cout << "foo\n"; }

  void bar() const            
  { cout << "bar\n"; }

  void foo2(const C& d)
  { cout << "foo2\n"; }
};

int main()
{
  C a;
  const C b;
  C d;

  a.foo();  
  a.bar();   
  a.foo2(d);

  b.foo();   
  b.bar();  

  return 0;
}


Now, object d isn't constant when declared, but it's passed as a constant reference to the function. What can be done with it now (in the function)? I assume member variables can be changed because the this pointer points to object a, or am I wrong?

Wow, I'm getting confused...

And ALL member functions should be made constant if they don't modify a member variable?
Last edited on
If you have a const pointer/reference, it doesn't matter if the object it points/refers to is const or not. For the purposes of the pointer/reference, it is const. Example:

1
2
3
4
5
6
7
8
C a;
const C& r = a;
const C* p = &a;

 // assuming foo is nonconst
a.foo();  // works fine, a is nonconst
r.foo();  // error, refers to const
p->foo(); // error, points to const 


Even though r, p, and a all refer to the same object, it is treated as const in some instances and nonconst in others.

Note that you can assign any nonconst object to a const pointer/reference, but cannot go the other way (without explicit casting)

1
2
3
4
5
C a;
const C& ra = a;  // okay

const C b;
C& rb = b;     // error 


const_cast can be used to get around this, but it should only be used in extreme circumstances (so extreme that I can't even come up with a practical example).

And ALL member functions should be made constant if they don't modify a member variable?


Well I want to stay away from always/never rules. There are instances where you might want to stray from the norm a bit. Generally speaking, though, yes. If a member function does not change the object in any way, then it should be made const.

Adding const correctness can be a pain if you didn't work it in from the beginning. Remember that const members functions cannot call nonconst member functions, so if you have the following:

1
2
3
4
5
6
7
8
9
10
11
class Example
{
  void bar()
  {
  }

  void foo()
  {
    bar();
  }
};


if you make 'foo' const, you'll also need to make 'bar' const. This can get ugly if the class is complicated.
Last edited on
Ok, thank you very much for the very clear explainations.

Wow, it will take months before I fully understand these pointer/reference/const/OOP topics :P
Wow... seems I stirred up a lively conversation on the topic.

Just to cite an example that is parallel to the original question:

1
2
3
4
5
// A stripped down example
class MyString {
   public:
       MyString operator+( const MyString& rhs );
};


Assume we have the above code. operator+ simply concatenates two strings. So
the intent is: MyString ("Hello" ) + MyString( "World" ) = MyString( "HelloWorld" ).

Now, the following code works fine:

1
2
3
4
// Assuming the appropriate constructors are implemented of course
MyString s1( "Hello" );
MyString s2( "World" );
MyString s3 = s1 + s2;


But the following code does not compile:
1
2
3
4
void Func( const MyString& s1, const MyString& s2 )
{
    MyString s3 = s1 + s2;
}


Why? Because the compiler wants to call operator+ on object s1 with object s2 as parameter. But object s1 is const, and operator+ is not a const function, therefore the compiler cannot call it. (Note: if you change s1 to a non-const reference or pass-by-value, the code compiles fine.)

Clearly, however, operator+ would modify neither s1 nor s2, just the same as

1
2
3
int a = 5;
int b = 4;
int x = a + b;


does not modify a or b in order to perform the addition.

Moral to the story: Any time a member function of a class does not modify any of its data members, the member function should be declared const.
You can also approach the problem from the standard c++ pointer point of view.

If you have a constant object for example const MyString a and you call a
member function on that object - for example a.func1(), then the this pointer is a pointer-to-constantobject
This is what happens when you call a constant member function - the this pointer is treated as such a pointer..

If you have a non-constant object for example MyString a and you call a
member function on that object - for example a.func(), then the this pointer is
a pointer-to-non-constantobject

So if you call a constant member function which tries to call a non-constant member function, an
implicit cast cast would be required on the this pointer - and in c++, compilers do not
implicitly cast a pointer-to-constant object to a pointer-to-non-constant object

EDIT:
The same goes for references
Last edited on
Ok, I think I understand it. Thank you very much for all the replies here :)
Topic archived. No new replies allowed.