Yes you can.
If you have
MyClass m;
m.doSomething();
The non-const version will be called. When you have
const MyClass m;
m.doSomething();
The const version will be called.
Yes you can.
If you have
MyClass m;
m.doSomething();
The non-const version will be called. When you have
const MyClass m;
m.doSomething();
The const version will be called.
Yes, you can do this. (@Job, this is not overload on return type, this is overload on 'const-state' of the called class instance)
If the instance is const, the second variant will be called, if it isn't, the first one is called. The practical use is that if the method is called on a const instance, you probably also want to return a "const String&" (e.g. if you return a reference to a member of the class), like this:
//function which can modify member
String& MyClass::doSomething();
//constant member function
const String& MyClass::doSomething() const;
Not only is this possible, it as a commonly used idiom.
For example, if the const
version of a function is called, a reference to a read-only version of a result can be returned. But if the non-const
version is called, a copy is constructed and returned that the receiver may modify. By implementing a const
version, we are saved from performing the construction when we know it isn't going to be needed.
The easy way to understand this, is to think of the object you are calling the method on as the 0th parameter:
e.g.: Think of
String& MyClass::doSomething();
MyClass mc;
mc.doSomething();
as a fancy, compiler supported way of doing this:
String& MyClass_doSomething(MyClass *this);
MyClass mc;
MyClass_doSomething(&mc);
Now, overloading based on constness is just a special case of overloading by parameter types:
String& MyClass::doSomething();
String& MyClass::doSomething() const;
can by thought of as something like this:
String& MyClass_doSomething(MyClass *this);
String& MyClass_doSomething(const MyClass *this);
As to the usefullness of this, the easiest examples are the begin
and end
methods on various std::
containers. If the vector
/string
/whatever is non const, and you call begin()
, you'll get back an iterator
that can be used to modify the contents of the original container. Clearly, this shouldn't be allowed for containers marked const
, so, thanks to the const/non const overloading, calling begin()
on a const vector return a const_iterator
that can be used to read the contents of the vector, but not modify it.
e.g.
string nc = "Hello world";
for (string::iterator iString = nc.begin(); iString != nc.end(); ++iString)
{
cout << *iString;; // legal to read
*iString = toupper(*iString); // legal to write
}
const string c = "Hello world again";
for (string::const_iterator iString = c.begin(); iString != c.end(); ++iString)
{
cout << *iString;; // legal to read
// *iString = toupper(*iString); // Writing is illegal
}
As to overloading by return type, you can't do it in C++. However, you can simulate it fairly decently.
This is how iterator is used. You have a const iterator as well as a non-const one.