16

I am very confused about the const version and non-const version member function like below:

value_type& top() { return this.item }
const value_type& top() const { return this.item }

What is the difference between these two functions? In what situation would they be used?

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
Yongwei Xing
  • 12,983
  • 24
  • 70
  • 90
  • 1
    You should consider getting one of the excellent introductory books listed in [The Definitive C++ Book Guide and List](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – James McNellis Jun 18 '10 at 02:29
  • 1
    Nitpick: `mutable` is a C++ keyword with its own meaning and is not simply the opposite of `const`. Your question would be more clearly phrased as "What's the difference between a const member function and a non-const member function?" – Josh Kelley Jun 18 '10 at 02:52
  • 1
    @Josh - good point about explicit disambiguation, but I think 'mutable' is common enough description, in programming languages, of 'something you can modify'. – Stephen Jun 18 '10 at 02:57
  • @Josh: I agree and have updated the question accordingly. If anyone is offended by this, feel free to rollback :) – fredoverflow Jun 18 '10 at 05:25
  • @Josh: You are right. mutable is not so precise as non-const – Yongwei Xing Jun 18 '10 at 06:55

5 Answers5

17

In short, they're used to add 'const correctness' to your program.

value_type& top() { return this.item }

This is used to provide mutable access to item. It is used so you can modify the element in the container.

For example:

c.top().set_property(5);  // OK - sets a property of 'item'
cout << c.top().get_property();  // OK - gets a property of 'item'

One common example for this pattern is returning mutable access to an element with vector::operator[int index].

std::vector<int> v(5);
v[0] = 1;  // Returns operator[] returns int&.

On the other hand:

const value_type& top() const { return this.item }

This is used to provide const access to item. It's more restrictive than the previous version - but it has one advantage - you can call it on a const object.

void Foo(const Container &c) {
   c.top();  // Since 'c' is const, you cannot modify it... so the const top is called.
   c.top().set_property(5);  // compile error can't modify const 'item'.
   c.top().get_property();   // OK, const access on 'item'. 
}

To follow the vector example:

const std::vector<int> v(5, 2);
v[0] = 5;  // compile error, can't mutate a const vector.
std::cout << v[1];  // OK, const access to the vector.
Stephen
  • 47,994
  • 7
  • 61
  • 70
6

The const-qualified member function will be called if the member function is called on an object that is const-qualified.

The non-const-qualified member function will be called if the member function is called on an object that is not const-qualified.

For example:

MyStack s;
s.top(); // calls non-const member function

const MyStack t;
t.top(); // calls const member function

Note that the same rules apply when calling a member function on a reference to an object or through a pointer to an object: if the pointer or reference is to a const object, the const member function will be called; otherwise the non-const member function will be called.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • If there is a memeber function like value_type& top() const { return this.item }, can a non-const object call it? If add const like function foo() const, it means that it would change the current object, is it right? If so, it should be called by non-const or const object. Is it right? – Yongwei Xing Jun 18 '10 at 02:30
  • If an object is not const and there are both const and non-const overloads of a member function (and those overloads are otherwise the same), then the non-const member function will be called. You can "force" the const member function to be called by casting the object to a const reference and then calling the member function on that. A const member function cannot modify any non-mutable members of the object nor can it call any non-const member functions. – James McNellis Jun 18 '10 at 02:34
  • @Yongwei Xing, to add to James's response, if you give only a "const" overload, it will be used by both const and non-const objects. It's only if you have both a const and non-const overload, where they will use different versions. In general, if something can be declared "const", then it should be... non-const objects can invoke both const and non-const functions, while const objects can only invoke const-qualified member functions. – Michael Aaron Safyan Jun 18 '10 at 04:40
4

If you have

class Foo
{
    value_type& top() { return this.item }
    const value_type& top() const { return this.item }
}

If you have

Foo foo;
const Foo cfoo;

The return types when you call top() are as follows:

value_type& bar = foo.top();
const value_type& cbar = cfoo.top();

In other words - if you have a constant instance of your class, the const version of the function is chosen as the overload to call.

The reason for this (in this particular case) is so that you can give out references to members (like item in this case) from a const instance of a class, and ensure that they too are const - thus unmodifiable and therefore preserving the const-ness of the instance they came from.

Andrew Russell
  • 26,924
  • 7
  • 58
  • 104
0

When member function is declared as const what's happening is that the implicit this pointer parameter passed to the function is typed to be a pointer to a const object. This allows the function to be called using a const object instance.

value_type& top();    // this function cannot be called using a `const` object
const value_type& top() const; // this function can be called on a `const` object
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

value_type& top() { return this.item; } ensures that either the calling object's data members can be modified or the return value can be.

value_type& top() const { return this.item; } ensures that the calling object's data members can't be modified, but the return value can be. So, for example, if I perform value_type item_of_x = x.top();, item_of_x can be modified but x cannot. Otherwise, a compiler error occurs (such as having the code this.item = someValue; inside of the function body).

const value_type& top() { return this.item; } ensures that the calling object's data members are allowed to be modified, but the return value cannot be. It's the opposite of what is discussed above: if I perform const value_type item_of_x = x.top();, item_of_x can't be modified but x can. NOTE value_type item_of_x = x.top(); still allows for modification of item_of_x, as item_of_x is now non-const.

const value_type& top() const { return this.item; } ensures that neither the calling object's data members can be modified nor the return value can be.

Don Larynx
  • 685
  • 5
  • 15