What's the Difference Between a Const Member Function and a Non-Const Member Function

What's the difference between a const member function and a non-const member function?

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.

Why the need for both const reference and const member function?

  1. return a const reference to prevent the function to change the returning value
  2. a const member function that cannot modify the object. in this case, it would be like this

This could have been a bit more clearer, I'll try my shot at explaining it better.

Returning a const reference prevent the returned object to be mutated by callers.

Here's an example:

// let get_name be `const std::vector<std::string>& get_name()`

np1.get_name().size(); // ok, size is a const function of vector
np1.get_name().push_back("hello"); // ERROR! push_back is not a const function of vector

So indeed, a caller cannot change the name vector. The return type is const qualified.

However, if the function get_name itself is not const qualified (not the return type), then it is allowed to change name from the class itself.

You see, member functions receive a hidden this parameter, which is a pointer to the object being called on. The pointer can either point to a const object, or a mutable object. Here's the comparison:

// returning const ref, callers cannot change the name vector
const std::vector<std::string>& get_name() {
// The function receive a `this` that points to a mutable,
// we can change the name from the inside
this->name.push_back("another");
return name;
}

// the `this` pointer points to const -----v---v
const std::vector<std::string>& get_name() const {
this->name.push_back("another"); // ERROR! Cannot mutate member of const object
return name;
}

Const-qualified member function are really useful for the caller, as it knows that whenever this function is called, its state won't change.

For example, not only you know that the vector::size() function won't mutate the vector, but the compiler guarantees it since it's a const qualified member function.

And for the last bit, the code you posted here:

vector<string> get_name() const { return name; } 

This will not return a reference, but will make a copy. The caller can mutate the copy however it wants, but cannot mutate name itself.

Here's an example of a copy mutated:

auto name_copy = np1.get_name();

name_copy.push_back("another name"); // works, we mutated the copy by adding an element

C++ Const Member Function (Beginner)

The quote is correct.

Try this

class TestClass
{
public:
void nonconst(){};

void constMethod() const {}
};

int main()
{

TestClass const *s = new TestClass();
//s->nonconst(); // (1) no not legal
s->constMethod();

s = new TestClass(); // (2) yes legal
s->constMethod();
}
  1. s is a pointer to a constant. Calling a non const method causes

passing ‘const TestClass’ as ‘this’ argument discards qualifiers [-fpermissive]


  1. However s can point to a different instance. As said in the comments the pointer can be pointed to a different variable.

Resolve const and non-const member function pointer

You may use:

template <typename T>
void doWork(void (T::*fun)() const){
const A a;
(a.*fun)();
}

A more generic function template would use const T a.

template <typename T>
void doWork(void (T::*fun)() const){
const T a;
(a.*fun)();
}

Note that the second version does not assume A anywhere.

Calling non const method in const method

The point is who is const in the const member function, the pointer ? the pointee ?

In the const member function f, ptr_, i.e. the pointer itself is considered as const, but not the object pointed by it. You're calling non-const member function g on the pointee, then it's fine.

Furthermore, you can't perform any modification (and call non-const member function) on the pointer ptr_ itself (same as obj_), like ptr_ = std::make_shared<B>();; but you can do this on the object pointed by it, like *ptr_ = B{};.

How to prefer calling const member function and fallback to non-const version?

This seems to work:

#include <type_traits>
#include <iostream>

template<typename T, typename=void>
struct find_a_drink {

void operator()(T &t) const
{
t.get_drink();
}
};

template<typename T>
struct find_a_drink<T,
std::void_t<decltype( std::declval<const T &>()
.get_drink())>
> {

void operator()(T &t) const
{
static_cast<const T &>(t).get_drink();
}
};

template<typename T>
void drink_from(T &&t)
{
find_a_drink<std::remove_reference_t<T>>{}(t);
}

/// v1
class Bar1
{
public:
void get_drink()
{
std::cout << "non-const get_drink() called (Bar1)" << std::endl;
}
};

class Bar2
{
public:
void get_drink()
{
std::cout << "non-const get_drink() called (Bar2)" << std::endl;
}

void get_drink() const
{
std::cout << "const get_drink() called (Bar2)" << std::endl;
}
};

int main()
{
Bar1 b1;
Bar2 b2;

drink_from(b1);
drink_from(b2);
return 0;
}

Result:

non-const get_drink() called (Bar1)
const get_drink() called (Bar2)

Call non-const function on a const object

Yes. Remember two things-

  1. If the function is non-constant, it can only be called by a
    non-constant object.
  2. If the function is constant, it can be called on any objects (I mean
    any constant or non-constant objects.)

Reasons:

  1. If the function is non-constant, then the function is allowed to
    change values of the object on which it is being called. So the
    compiler doesn't allow to create this chance and prevent you to call
    a non-constant function on a constant object, as constant object
    means you cannot change anything of it anymore. So the compiler only
    allows you to call it on a non-constant object as this object can be
    modified.
  2. If the function is constant itself, then it is promising that it
    won't change anything of the object on which it is being called. So
    the compiler doesn't care whether you are calling a constant
    function on a constant or non-constant object as the function itself
    is unable to change the object.


Related Topics



Leave a reply



Submit