What are the semantics of a const member function? - c++

I understand that the function is not allowed to change the state of the object, but I thought I read somewhere that the compiler was allowed to assume that if the function was called with the same arguments, it would return the same value and thus could reuse a cached value if it was available. e.g.
class object
{
int get_value(int n) const
{
...
}
...
object x;
int a = x.get_value(1);
...
int b = x.get_value(1);
then the compiler could optimize the second call away and either use the value in a register or simply do b = a;
Is this true?

const is about program semantics and not about implementation details. You should mark a member function const when it does not change the visible state of the object, and should be callable on an object that is itself const. Within a const member function on a class X, the type of this is X const *: pointer to constant X object. Thus all member variables are effectively const within that member function (except mutable ones). If you have a const object, you can only call const member functions on it.
You can use mutable to indicate that a member variable may change even within a const member function. This is typically used to identify variables used for caching results, or for variables that don't affect the actual observable state such as mutexes (you still need to lock the mutex in the const member functions) or use counters.
class X
{
int data;
mutable boost::mutex m;
public:
void set_data(int i)
{
boost::lock_guard<boost::mutex> lk(m);
data=i;
}
int get_data() const // we want to be able to get the data on a const object
{
boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
return data;
}
};
If you hold the data by pointer rather than directly (including smart pointers such as std::auto_ptr or boost::shared_ptr) then the pointer becomes const in a const member function, but not the pointed-to data, so you can modify the pointed-to data.
As for caching: in general the compiler cannot do this because the state might change between calls (especially in my multi-threaded example with the mutex). However, if the definition is inline then the compiler can pull the code into the calling function and optimize what it can see there. This might result in the function effectively only being called once.
The next version of the C++ Standard (C++0x) will have a new keyword constexpr. Functions tagged constexpr return a constant value, so the results can be cached. There are limits on what you can do in such a function (in order that the compiler can verify this fact).

The keyword mutable on member variables allows for const functions to alter the state of the object at hand.
And no, it doesn't cache data (at least not all calls) since the following code is a valid const function that changes over time:
int something() const { return m_pSomeObject->NextValue(); }
Note that the pointer can be const, though the object pointed to is not const, therefore the call to NextValue on SomeObject may or may not alter it's own internal state. This causes the function something to return different values each time it's called.
However, I can't answer how the compiler works with const methods. I have heard that it can optimize certain things, though I'd have to look it up to be certain.

No.
A const method is a method that doesn't change the state of the object (i.e. its fields), but you can't assume that given the same input, return value of a const method is determined. In other words, const keyword does NOT imply that the function is one-to-one. For instance a method that returns the current time is a const method but its return value changes between calls.

The const keyword on a member function marks the this parameter as constant. The function can still mute global data (so can't be cached), but not object data (allowing for calls on const objects).

In this context, a const member function means that this is treated as a const pointer also. In practical terms, it means you aren't allowed to modify the state of this inside a const member function.
For no-side-effect functions (i.e., what you're trying to achieve), GCC has a "function attribute" called pure (you use it by saying __attribute__((pure))): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

I doubt it, the function could still call a global function that altered the state of the world and not violate const.

On top of the fact that the member function can modify global data, it is possible for the member function to modify explicitly declared mutable members of the object in question.

Corey is correct, but bear in mind that any member variables that are marked as mutable can be modified in const member functions.
It also means that these functions can be called from other const functions, or via other const references.
Edit: Damn, was beaten by 9 seconds.... 9!!! :)

const methods are also allowed to modify static locals. For example, the following is perfectly legal (and repeated calls to bar() will return increasing values - not a cached 0):
class Foo
{
public:
int bar() const
{
static int x = 0;
return x++;
}
};

Related

Does this code subvert the C++ type system?

I understand that having a const method in C++ means that an object is read-only through that method, but that it may still change otherwise.
However, this code apparently changes an object through a const reference (i.e. through a const method).
Is this code legal in C++?
If so: Is it breaking the const-ness of the type system? Why/why not?
If not: Why not?
Note 1: I have edited the example a bit, so answers might be referring to older examples.
Edit 2: Apparently you don't even need C++11, so I removed that dependency.
#include <iostream>
using namespace std;
struct DoBadThings { int *p; void oops() const { ++*p; } };
struct BreakConst
{
int n;
DoBadThings bad;
BreakConst() { n = 0; bad.p = &n; }
void oops() const { bad.oops(); } // can't change itself... or can it?
};
int main()
{
const BreakConst bc;
cout << bc.n << endl; // 0
bc.oops(); // O:)
cout << bc.n << endl; // 1
return 0;
}
Update:
I have migrated the lambda to the constructor's initialization list, since doing so allows me to subsequently say const BreakConst bc;, which -- because bc itself is now const (instead of merely the pointer) -- would seem to imply (by Stroustrup) that modifying bc in any way after construction should result in undefined behavior, even though the constructor and the caller would have no way of knowing this without seeing each others' definitions.
The oops() method isn't allowed to change the constness of the object. Furthermore it doesn't do it. Its your anonymous function that does it. This anonymous function isn't in the context of the object, but in the context of the main() method which is allowed to modify the object.
Your anonymous function doesn't change the this pointer of oops() (which is defined as const and therefore can't be changed) and also in no way derives some non-const variable from this this-pointer. Itself doesn't have any this-pointer. It just ignores the this-pointer and changes the bc variable of the main context (which is kind of passed as parameter to your closure). This variable is not const and therefore can be changed. You could also pass any anonymous function changing a completely unrelated object. This function doesn't know, that its changing the object that stores it.
If you would declare it as
const BreakConst bc = ...
then the main function also would handle it as const object and couldn't change it.
Edit:
In other words: The const attribute is bound to the concrete l-value (reference) accessing the object. It's not bound to the object itself.
You code is correct, because you don't use the const reference to modify the object. The lambda function uses completely different reference, which just happen to be pointing to the same object.
In the general, such cases does not subvert the type system, because the type system in C++ does not formally guarantee, that you can't modify the const object or the const reference. However modification of the const object is the undefined behaviour.
From [7.1.6.1] The cv-qualifiers:
A pointer or reference to a cv-qualified type need not actually point
or refer to a cv-qualified object, but it is treated as if it does; a
const-qualified access path cannot be used to modify an object even if
the object referenced is a non-const object and can be modified through
some other access path.
Except that any class member declared mutable (7.1.1) can be modified,
any attempt to modify a const object during its lifetime (3.8) results
in undefined behavior.
I already saw something similar. Basically you invoke a cost function that invoke something else that modifies the object without knowing it.
Consider this as well:
#include <iostream>
using namespace std;
class B;
class A
{
friend class B;
B* pb;
int val;
public:
A(B& b);
void callinc() const;
friend ostream& operator<<(ostream& s, const A& a)
{ return s << "A value is " << a.val; }
};
class B
{
friend class A;
A* pa;
public:
void incval() const { ++pa->val; }
};
inline A::A(B& b) :pb(&b), val() { pb->pa = this; }
inline void A::callinc() const { pb->incval(); }
int main()
{
B b;
const A a(b); // EDIT: WAS `A a(b)`
cout << a << endl;
a.callinc();
cout << a << endl;
}
This is not C++11, but does the same:
The point is that const is not transitive.
callinc() doesn't change itself a and incval doesn't change b.
Note that in main you can even declare const A a(b); instead of A a(b); and everything compile the same.
This works from decades, and in your sample you're just doing the same: simply you replaced class B with a lambda.
EDIT
Changed the main() to reflect the comment.
The issue is one of logical const versus bitwise const. The compiler
doesn't know anything about the logical meaning of your program, and
only enforces bitwise const. It's up to you to implement logical const.
This means that in cases like you show, if the pointed to memory is
logically part of the object, you should refrain from modifying it in a
const function, even if the compiler will let you (since it isn't part
of the bitwise image of the object). This may also mean that if part of
the bitwise image of the object isn't part of the logical value of the
object (e.g. an embedded reference count, or cached values), you make it
mutable, or even cast away const, in cases where you modify it without
modifying the logical value of the object.
The const feature merely helps against accidental misuse. It is not designed to prevent dedicated software hacking. It is the same as private and protected membership, someone could always take the address of the object and increment along the memory to access class internals, there is no way to stop it.
So, yes you can get around const. If nothing else you can simply change the object at the memory level but this does not mean const is broken.

is this destructor valid in c++?

String::~String() {
std::cout<<"String()" <<std::endl;
}
I wonder if this implementation of destructor is valid?
And another question about const member function qualifier, I know the const function can not change the variables in this class, it just read-only. If there is no other weird questions about it, I think I can understand it, but I saw some questions as following:
It allows the invocation of a non-const member function for the object pointed to by this
It guarantees that only mutable member variables of the object pointed to by this can be changed
It ensures that all constants remain invariable
It prevents inheritance
It allows changes to the state of the object pointed to by this
Based on my understanding, it is very hard to check which one is right, so I guess all of them are wrong?
The destructor is technically just another function, there doesn't seem anything wrong syntactically with this destructor to me, so it seems valid
That is all there is to const member functions, you cannot modify the data. These functions are automatically invoked by a const instance of the class. So if you have two functions with the same signature except for const-ness, it will chose the const version for const instances, and for non-const instances, it will depend on how you use it that determines which version is invoked
a) you cannot invoke non-const member functions within a const member function
b)Correct
c) correct
d) i'm unsure what you mean by preventing inheritance. IF you declare a function as virtual, const or not, it is inherited and can be overridden by subclasses
e) in const member functions, all data is considered const, unless declared a mutable.
Yes, that is a valid destructor.
const does not prevent inheritance. Nor does it bring about invariant behavior in the class's methods.
This question is actually multiple questions, though.
I recommend reading C++ FAQS.
I wonder if this implementation of destructor is valid?
There is nothing wrong with the destructor. But the question is: is that all you want to do in the destructor? Destructor is usually used to free the resources object holds when its alive; so it should free them when its going to die, so that others can use them. If it doesn't free them, then those resources will not be used by others as long as the program runs. Such a situation is usually referred to as Resource Leak, and if the resource is memory, its called Memory Leak.
Regarding question 2.
A nice way to think of member function cv qualifiers is to think of them as qualifiers on the 'this' pointer.
For example, if we wrote some C++ code in C:
class A
{
public:
void f1 ();
void f2 () const;
private:
int i;
};
This is the same as the following C code:
struct A
{
int i;
};
void f1 (A * const this); // Non const member
void f2 (A const * const this); // Const member
Another important thing to understand is that when you refer to a non static data member of a class, (*this). is implicitly added to it:
void A::f1 ()
{
i = 0; // This and the next line have the same meaning
(*this).i = 0;
}
When the member function is const, the this pointer is declared as pointing to a const object:
void A::f2 () const
{
(*this).i = 0; // Error '*this' is const, so cannot modify (*this).i
}
One of the conclusions from this, and something that people sometimes find is surprising, is that a const member function can still modify data pointed to by a member pointer. For example:
class A
{
public:
void f () const
{
*i = 0;
}
private:
int * i;
};
This looks wrong, but it's actually fine. (*this).i is const and so you would not be able to change what i points to, but i is still a pointer to a non const int and so we can modify the value pointed to by i.

confusion on a const function that is calling a non-const function

Basically there are three classes I defined: paralelogram, point and line classes, and paralelogram has some vectors of points and lines, and in the paralelogram class I am defining a compute_area function as
double Paralelogram::compute_area() const
{
assert( !points.empty() );
double h = points[3].distance_to_line( lines[0] ); // point[3] is the last point in
// the vector however it is not a
// const object, and this gives a
// compile time error
double base = points[0].distance_to_point( points[1] );
return base*h;
}
Edit distance_to_line function is non-const
double Point::distance_to_line(Line& l)
{
return l.distance_to_point(*this);
}
deleting the const from the function definition and declaration solves the problem, however my reasoning, while coding, was compute_area does not modify the object so it can be const, however this is right as long as it operates on const objects and calls functions of const objects, right?
If the point objects are not const also, this is not valid anymore. And since they are not const that is the reason why it works after the const removal.
This is a puzzling point for me where I do not modify the object however the objects it uses gives the problem and moreover what I am thinking I am still not changing those objects as well, but apparently there is a confusion in my const understanding. One more thing, is this somehow related to the this pointer of the Paralelogram class if yes can you clarify?
In a const function, types of every member becomes const in such a way that you cannot modify them (unless they're declared mutable), nor can you call any non-const function using them.
It seems that in your code, distance_to_line is non-const function, but you're calling it from a const function, that means inside const function points[3] and points[0] becomes const object, so you cannot call non-const function (which I believe distance_to_line is) on const object.
--
EDIT:
You need to make distance_to_line a const function, and since this function calls distance_to_point, you've to make even distance_to_point const function.
To make a member function const, you don't need to make the member variables const as well. You just need to ensure that your const function does not modify any of the member variables of the class.
Have you tried making the distance_to_line() function const on the point class? If that works, you'll also probably need to make distance_to_point() const as well. If these aren't const, the compiler can't ensure that the calling function is also const.
Make distance_to_line() and distance_to_point() const and your error will go away.
By declaring the function const, you're also restricting your access to any members - they'll be treated as if they were const as well. Since you can't call a non-const member function on a const object, those calls will fail.

const and no const methods in c++?

I have a program and many of its classes have some operators and methods with the keyword const like the followings:
operator const char* () const;
operator char* ();
void Save(const char *name) const;
void Load(const char *name);
First: what does it mean const at the end of the method declaration?, is it the same like putting it at the beginning?
Second: Why would be a const version and a no const version of operator() needed?
Thanks in advance.
First: what does it mean const at the end of the method declaration?, is it the same like putting it at the beginning?
No. A const at the end means that the method may be called on objects that are declared const. A const at the beginning means that the returned value is const.
Second: Why would be a const version and a no const version of operator() needed?
The non-const version returns a char* which is not const. By modifying this char* you could then in fact modify the object (assuming the char* is a member of the object).
Since this is not allowed for const objects, there's an overload of operator() for const objects, so that a const char* is returned, so the object can't be modified through it.
'const' at the end tells the compiler that this method does not change any member variables - that it is safe to call this method on const instances. So, Save could be called on a const instance, since it won't change that instance. Load on the other hand, will change the instance so can't be used on const instances.
The const version of operator() passes back a const pointer, guaranteeing the buffer passed back won't change. Presumably that's a pointer into a instance variable of the class. For non-const instances, the other operator() passes back a non-const pointer. It would have to be a pointer to some memory that even if written to, wouldn't change the contents of the instance.
Also, look up the 'mutable' keyword sometime. Understanding that will help you understand this idea of const-correctness.
Member function constness. It means the function can not(*) modify any of your member variables. It's like putting a const in front of all your member variables for this one function call. It's a good guarantee for the clients of your class and may also aid in compiler optimisations.
(*) - see also the keyword mutable.
Putting const at the end of a method declaration is stating that the object itself, or this, is const instead of the return type.
C++ allows methods to be overloaded on const for complicated reasons. Not enough space to go into full detail here. But here are a couple of short ones.
Ocassionally there is value, or flat necessity, in having a method behave differently when it is called from a const type. The most straight forward example is when you want to return a const value from a const method and a non-const value from a normal method.
Whether or not this is const dramatically changes the binding of the internal method. To the point that it would essentially become two different method bodies. Hence it makes sense to break it up into 2 different methods.
One note in addition to the other answers: there is no operator() in your example.
operator const char* () const;
operator char* ();
are conversion operators, which mean that objects of the class can be implicitly converted to C-style strings, like
void f(const MyClass& x, MyClass& y) {
const char* x_str = x;
char* y_str = y;
}
A declaration and usage of operator(), which means you can use an object of the class type sort of like a function, would look like:
class MyClass {
public:
const char* operator() (int x, int y) const;
// ...
};
void g(const MyClass& obj) {
const char* result = obj(3, 4);
}
If you're looking for a great resource on C++ (including tips on using const correctly) try "Effective C++".
A useful site about this: JRiddel.org
In C++ when you declare a method const by putting it AFTER the method signature you are asserting that "This method will not change any non-mutable instance variables in the object it is being called on."
The const before the return value (e.g. the const in: operator const char*...") is declaring that it only returns a variable pointer to a const char*. (You may not change the contents of the char* but you can re-assign the pointer.) If you wrote "const char* const ..." it would be a constant pointer to constant characters. (The const comes after the star).
The multiple versions are useful so the compiler can understand this:
const char* my_const_var = <object_name>();
char* my_var = <object_name>();
Chris
You should refer to the "HIGH·INTEGRITY C++ CODING STANDARD MANUAL" for knowing when it is recommended to use the const modifier for class members:
High Integrity CPP Rule 3.1.8: Declare 'const' any class member function that does not modify the externally visible state of the object. (QACPP 4211, 4214)
Justification: Although the language enforces bitwise const correctness, const correctness should be thought of as logical, not bitwise. A member function should be declared const if it is impossible for a client to determine whether the object has changed as a result of calling that function. The 'mutable' keyword can be used to declare member data which can be modified in const functions, this should only be used where the member data does not affect the externally visible state of the object.
class C
{
public:
const C& foo() { return * this; } // should be declared const
const int& getData() { return m_i; } // should be declared const
int bar() const { return m_mi; } // ok to declare const
private:
int m_i;
mutable int m_mi;
};
Reference Effective C++ Item 21;Industrial Strength C++ 7.13;
Const at the beginning applies to the return value. Const at the end applies to the method itself. When you declare a method as "const" you are saying that you have no intention of modifying any of the member variables of the class in the method. The compiler will even do some basic checks to make sure that the method doesn't modify member variables. The const in the return value prevents the caller from modifying the value that is returned. This can be useful when you return pointers or references to data managed by the class. This is often done to avoid returning copies of complex data which could be expensive at run time.
The reason you have two different operators is that the "const" version returns a const pointer to what is probably data internal to the class. If the instance of the class is const, then chances are you want the data being return should also be const. The "non-const" version just provides a method that returns a modifiable return value when the caller has a non-const instance of the class.

Which are the implications of return a value as constant, reference and constant reference in C++?

I'm learning C++ and I'm still confused about this. What are the implications of return a value as constant, reference and constant reference in C++ ? For example:
const int exampleOne();
int& exampleTwo();
const int& exampleThree();
Here's the lowdown on all your cases:
• Return by reference: The function call can be used as the left hand side of an assignment. e.g. using operator overloading, if you have operator[] overloaded, you can say something like
a[i] = 7;
(when returning by reference you need to ensure that the object you return is available after the return: you should not return a reference to a local or a temporary)
• Return as constant value: Prevents the function from being used on the left side of an assignment expression. Consider the overloaded operator+. One could write something like:
a + b = c; // This isn't right
Having the return type of operator+ as "const SomeType" allows the return by value and at the same time prevents the expression from being used on the left side of an assignment.
Return as constant value also allows one to prevent typos like these:
if (someFunction() = 2)
when you meant
if (someFunction() == 2)
If someFunction() is declared as
const int someFunction()
then the if() typo above would be caught by the compiler.
• Return as constant reference: This function call cannot appear on the left hand side of an assignment, and you want to avoid making a copy (returning by value). E.g. let's say we have a class Student and we'd like to provide an accessor id() to get the ID of the student:
class Student
{
std::string id_;
public:
const std::string& id() const;
};
const std::string& Student::id()
{
return id_;
}
Consider the id() accessor. This should be declared const to guarantee that the id() member function will not modify the state of the object. Now, consider the return type. If the return type were string& then one could write something like:
Student s;
s.id() = "newId";
which isn't what we want.
We could have returned by value, but in this case returning by reference is more efficient. Making the return type a const string& additionally prevents the id from being modified.
The basic thing to understand is that returning by value will create a new copy of your object. Returning by reference will return a reference to an existing object. NOTE: Just like pointers, you CAN have dangling references. So, don't create an object in a function and return a reference to the object -- it will be destroyed when the function returns, and it will return a dangling reference.
Return by value:
When you have POD (Plain Old Data)
When you want to return a copy of an object
Return by reference:
When you have a performance reason to avoid a copy of the object you are returning, and you understand the lifetime of the object
When you must return a particular instance of an object, and you understand the lifetime of the object
Const / Constant references help you enforce the contracts of your code, and help your users' compilers find usage errors. They do not affect performance.
Returning a constant value isn't a very common idiom, since you're returning a new thing anyway that only the caller can have, so it's not common to have a case where they can't modify it. In your example, you don't know what they're going to do with it, so why should you stop them from modifying it?
Note that in C++ if you don't say that something is a reference or pointer, it's a value so you'll create a new copy of it rather than modifying the original object. This might not be totally obvious if you're coming from other languages that use references by default.
Returning a reference or const reference means that it's actually another object elsewhere, so any modifications to it will affect that other object. A common idiom there might be exposing a private member of a class.
const means that whatever it is can't be modified, so if you return a const reference you can't call any non-const methods on it or modify any data members.
Return by reference.
You can return a reference to some value, such as a class member. That way, you don't create copies. However, you shouldn't return references to values in a stack, as that results in undefined behaviour.
#include <iostream>
using namespace std;
class A{
private: int a;
public:
A(int num):a(num){}
//a to the power of 4.
int& operate(){
this->a*=this->a;
this->a*=this->a;
return this->a;
}
//return constant copy of a.
const int constA(){return this->a;}
//return copy of a.
int getA(){return this->a;}
};
int main(){
A obj(3);
cout <<"a "<<obj.getA()<<endl;
int& b=obj.operate(); //obj.operate() returns a reference!
cout<<"a^4 "<<obj.getA()<<endl;
b++;
cout<<"modified by b: "<<obj.getA()<<endl;
return 0;
}
b and obj.a "point" to the same value, so modifying b modifies the value of obj.a.
$./a.out
a 3
a^4 81
modified by b: 82
Return a const value.
On the other hand, returning a const value indicates that said value cannot be modified. It should be remarked that the returned value is a copy.:
For example,
constA()++;
would result in a compilation error, since the copy returned by constA() is constant. But this is just a copy, it doesn't imply that A::a is constant.
Return a const reference.
This is similiar to returning a const value, except that no copy is return, but a reference to the actual member. However, it cant be modified.
const int& refA(){return this->a;}
const int& b = obj.refA();
b++;
will result in a compilation error.
const int exampleOne();
Returns a const copy of some int. That is, you create a new int which may not be modified. This isn't really useful in most cases because you're creating a copy anyway, so you typically don't care if it gets modified. So why not just return a regular int?
It may make a difference for more complex types, where modifying them may have undesirable sideeffects though. (Conceptually, let's say a function returns an object representing a file handle. If that handle is const, the file is read-only, otherwise it can be modified. Then in some cases it makes sense for a function to return a const value. But in general, returning a const value is uncommon.
int& exampleTwo();
This one returns a reference to an int. This does not affect the lifetime of that value though, so this can lead to undefined behavior in a case such as this:
int& exampleTwo() {
int x = 42;
return x;
}
we're returning a reference to a value that no longer exists. The compiler may warn you about this, but it'll probably compile anyway. But it's meaningless and will cause funky crashes sooner or later. This is used often in other cases though. If the function had been a class member, it could return a reference to a member variable, whose lifetime would last until the object goes out of scope, which means function return value is still valid when the function returns.
const int& exampleThree();
Is mostly the same as above, returning a reference to some value without taking ownership of it or affecting its lifetime. The main difference is that now you're returning a reference to a const (immutable) object. Unlike the first case, this is more often useful, since we're no longer dealing with a copy that no one else knows about, and so modifications may be visible to other parts of the code. (you may have an object that's non-const where it's defined, and a function that allows other parts of the code to get access to it as const, by returning a const reference to it.
Your first case:
const int exampleOne();
With simple types like int, this is almost never what you want, because the const is pointless. Return by value implies a copy, and you can assign to a non-const object freely:
int a = exampleOne(); // perfectly valid.
When I see this, it's usually because whoever wrote the code was trying to be const-correct, which is laudable, but didn't quite understand the implications of what they were writing. However, there are cases with overloaded operators and custom types where it can make a difference.
Some compilers (newer GCCs, Metrowerks, etc) warn on behavior like this with simple types, so it should be avoided.
I think that your question is actually two questions:
What are the implications of returning a const.
What are the implications of returning a reference.
To give you a better answer, I will explain a little more about both concepts.
Regarding the const keyword
The const keyword means that the object cannot be modified through that variable, for instance:
MyObject *o1 = new MyObject;
const MyObject *o2 = o1;
o1->set(...); // Will work and will change the instance variables.
o2->set(...); // Won't compile.
Now, the const keyword can be used in three different contexts:
Assuring the caller of a method that you won't modify the object
For example:
void func(const MyObject &o);
void func(const MyObject *o);
In both cases, any modification made to the object will remain outside the function scope, that's why using the keyword const I assure the caller that I won't be modifying it's instance variables.
Assuring the compiler that a specific method do not mutate the object
If you have a class and some methods that "gets" or "obtains" information from the instance variables without modifying them, then I should be able to use them even if the const keyword is used. For example:
class MyObject
{
...
public:
void setValue(int);
int getValue() const; // The const at the end is the key
};
void funct(const MyObject &o)
{
int val = o.getValue(); // Will compile.
a.setValue(val); // Won't compile.
}
Finally, (your case) returning a const value
This means that the returned object cannot be modified or mutated directly. For example:
const MyObject func();
void func2()
{
int val = func()->getValue(); // Will compile.
func()->setValue(val); // Won't compile.
MyObject o1 = func(); // Won't compile.
MyObject o2 = const_cast<MyObject>(func()); // Will compile.
}
More information about the const keyword: C++ Faq Lite - Const Correctness
Regarding references
Returning or receiving a reference means that the object will not be duplicated. This means that any change made to the value itself will be reflected outside the function scope. For example:
void swap(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
int a = 2; b = 3;
swap(a, b); // a IS THE SAME AS x inside the swap function
So, returning a reference value means that the value can be changed, for instance:
class Foo
{
public:
...
int &val() { return m_val; }
private:
int m_val;
};
Foo f;
f.val() = 4; // Will change m_val.
More information about references: C++ Faq Lite - Reference and value semantics
Now, answering your questions
const int exampleOne();
Means the object returned cannot change through the variable. It's more useful when returning objects.
int& exampleTwo();
Means the object returned is the same as the one inside the function and any change made to that object will be reflected inside the function.
const int& exampleThree();
Means the object returned is the same as the one inside the function and cannot be modified through that variable.
Never thought, that we can return a const value by reference and I don't see the value in doing so..
But, it makes sense if you try to pass a value to a function like this
void func(const int& a);
This has the advantage of telling the compiler to not make a copy of the variable a in memory (which is done when you pass an argument by value and not by reference). The const is here in order to avoid the variable a to be modified.