What is the meaning of 'const' at the end of a member function declaration?
Asked Answered
M

12

875

What is the meaning of const in declarations like these?

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};
Marrero answered 15/4, 2009 at 13:27 Comment(0)
P
1145

When you add the const keyword to a method the this pointer will essentially become a pointer to const object, and you cannot therefore change any member data. (Unless you use mutable, more on that later).

The const keyword is part of the functions signature which means that you can implement two similar methods, one which is called when the object is const, and one that isn't.

#include <iostream>

class MyClass
{
private:
    int counter;
public:
    void Foo()
    { 
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        std::cout << "Foo const" << std::endl;
    }

};

int main()
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
}

This will output

Foo
Foo const

In the non-const method you can change the instance members, which you cannot do in the const version. If you change the method declaration in the above example to the code below you will get some errors.

    void Foo()
    {
        counter++; //this works
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++; //this will not compile
        std::cout << "Foo const" << std::endl;
    }

This is not completely true, because you can mark a member as mutable and a const method can then change it. It's mostly used for internal counters and stuff. The solution for that would be the below code.

#include <iostream>

class MyClass
{
private:
    mutable int counter;
public:

    MyClass() : counter(0) {}

    void Foo()
    {
        counter++;
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++;    // This works because counter is `mutable`
        std::cout << "Foo const" << std::endl;
    }

    int GetInvocations() const
    {
        return counter;
    }
};

int main(void)
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
    std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}

which would output

Foo
Foo const
Foo has been invoked 2 times
Pipage answered 15/4, 2009 at 13:49 Comment(9)
What if I just make a const method but without a normal method, and then I call the method using a non-const object, my code usually runs fine. Is it wrong or harmful or something?Lunarian
@Lunarian That's completely fine, and is pretty normal pattern for read only members.Pipage
mutable and const makes sense to me. But what I don't quite understand is that if a const member function would like a member value to be changed, why not just discard const and make itself a non-const member function? Does it have something to do with speed? Or it's like given two member variables, one has a mutable keyword and another one doesn't, in a const member function, we would like to only change the value of the variable with mutable keyword but want to keep another intact?Sottish
const functions can help speed. If the compiler doesn't see the function's implementation (its defined in the cpp file, or calls functions defined in the cpp file), then it doesn't know which member variables it might change. If any of the member variables is held in registers just before the function was called, and are used after the function call, the compiler has to assume the values might have been changed, and reload them from memory. If the member variables are not mute, then the compiler can deduce the function did not change them, and can skip loading them from memory after the call.Nganngc
@UriRaz: Because of const_cast, the implementation cannot typically assume that member variables are left unmodified by opaque const member functions (unless of course it knows the complete object is const).Tripitaka
@DavisHerring There are ways to subvert const, such as creating a non-const pointer to the variable, and changing its value via the pointer. If implementations had to assume that constness is subverted outside the compilation unit, IMHO it would void the meaning and purpose of the keyword. AFAIK 1. The purpose of const_cast is not to turn a const into a variable, but to handle corner situations such as having to pass a constant as a non-const parameter to a function one can't change) and known not to change it. 2. Implementations may optimize assuming constness is not violated.Nganngc
@UriRaz: Implementations do have to assume such subversion. You are welcome to believe that a different language rule would be (or have been) a better choice, but it really is that way.Tripitaka
@DavisHerring You are welcome to cite your sources.Nganngc
@UriRaz: That should really be its own question, but it’s [dcl.type.cv]/3–4. It’s hard to see how const_cast could ever be used otherwise.Tripitaka
T
212

The const means that the method promises not to alter any members of the class. You'd be able to execute the object's members that are so marked, even if the object itself were marked const:

const foobar fb;
fb.foo();

would be legal.

See How many and which are the uses of “const” in C++? for more information.

Thee answered 15/4, 2009 at 13:29 Comment(0)
R
51

The const qualifier means that the methods can be called on any value of foobar. The difference comes when you consider calling a non-const method on a const object. Consider if your foobar type had the following extra method declaration:

class foobar {
  ...
  const char* bar();
}

The method bar() is non-const and can only be accessed from non-const values.

void func1(const foobar& fb1, foobar& fb2) {
  const char* v1 = fb1.bar();  // won't compile
  const char* v2 = fb2.bar();  // works
}

The idea behind const though is to mark methods which will not alter the internal state of the class. This is a powerful concept but is not actually enforceable in C++. It's more of a promise than a guarantee. And one that is often broken and easily broken.

foobar& fbNonConst = const_cast<foobar&>(fb1);
Resiniferous answered 15/4, 2009 at 13:30 Comment(3)
I thought the answer is about other const methods and not about const objects.Laoag
Thanks for the "The idea behind const though is to mark methods which will not alter the internal state of the class". That's really what I was looking for.Antebi
@Resiniferous does this mean that any member function representing a read-only operation should be marked as const?Antebi
L
32

These const mean that compiler will Error if the method 'with const' changes internal data.

class A
{
public:
    A():member_()
    {
    }

    int hashGetter() const
    {
        state_ = 1;
        return member_;
    }
    int goodGetter() const
    {
        return member_;
    }
    int getter() const
    {
        //member_ = 2; // error
        return member_;
    }
    int badGetter()
    {
        return member_;
    }
private:
    mutable int state_;
    int member_;
};

The test

int main()
{
    const A a1;
    a1.badGetter(); // doesn't work
    a1.goodGetter(); // works
    a1.hashGetter(); // works

    A a2;
    a2.badGetter(); // works
    a2.goodGetter(); // works
    a2.hashGetter(); // works
}

Read this for more information

Laoag answered 15/4, 2009 at 13:30 Comment(1)
A question on const member functions that doesn't mention mutable is incomplete at best.Leucopenia
S
14

Blair's answer is on the mark.

However note that there is a mutable qualifier which may be added to a class's data members. Any member so marked can be modified in a const method without violating the const contract.

You might want to use this (for example) if you want an object to remember how many times a particular method is called, whilst not affecting the "logical" constness of that method.

Stammer answered 15/4, 2009 at 13:37 Comment(0)
M
13

Meaning of a Const Member Function in C++ Common Knowledge: Essential Intermediate Programming gives a clear explanation:

The type of the this pointer in a non-const member function of a class X is X * const. That is, it’s a constant pointer to a non-constant X (see Const Pointers and Pointers to Const [7, 21]). Because the object to which this refers is not const, it can be modified. The type of this in a const member function of a class X is const X * const. That is, it’s a constant pointer to a constant X. Because the object to which this refers is const, it cannot be modified. That’s the difference between const and non-const member functions.

So in your code:

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};

You can think it as this:

class foobar
{
  public:
     operator int (const foobar * const this) const;
     const char* foo(const foobar * const this) const;
};
Mispronounce answered 14/3, 2017 at 5:48 Comment(1)
this is not const. The reason why it can't be modified is that it's a prvalue.Raspberry
C
11

I would like to add the following point.

You can also make it a const & and const &&

So,

struct s{
    void val1() const {
     // *this is const here. Hence this function cannot modify any member of *this
    }
    void val2() const & {
    // *this is const& here
    }
    void val3() const && {
    // The object calling this function should be const rvalue only.
    }
    void val4() && {
    // The object calling this function should be rvalue reference only.
    }

};

int main(){
  s a;
  a.val1(); //okay
  a.val2(); //okay
  // a.val3() not okay, a is not rvalue will be okay if called like
  std::move(a).val3(); // okay, move makes it a rvalue
}

Feel free to improve the answer. I am no expert

Caterpillar answered 26/3, 2019 at 17:24 Comment(2)
*this is always an lvalue, even if the member function is rvalue-ref-qualified and is called on an rvalue. Example.Moberg
Updated. Is that okay?Caterpillar
M
7

when you use const in the method signature (like your said: const char* foo() const;) you are telling the compiler that memory pointed to by this can't be changed by this method (which is foo here).

Maeda answered 30/5, 2015 at 5:54 Comment(0)
T
6

Here const means that at that function any variable's value can not change

class Test{
private:
    int a;
public:
    void test()const{
        a = 10;
    }
};

And like this example, if you try to change the value of a variable in the test function you will get an error.

Tauten answered 20/12, 2020 at 17:7 Comment(0)
I
3

The const keyword used with the function declaration specifies that it is a const member function and it will not be able to change the data members of the object.

Im answered 18/8, 2019 at 9:5 Comment(0)
S
2

https://isocpp.org/wiki/faq/const-correctness#const-member-fns

What is a "const member function"?

A member function that inspects (rather than mutates) its object.

A const member function is indicated by a const suffix just after the member function’s parameter list. Member functions with a const suffix are called “const member functions” or “inspectors.” Member functions without a const suffix are called “non-const member functions” or “mutators.”

class Fred {
public:
  void inspect() const;   // This member promises NOT to change *this
  void mutate();          // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
  changeable.inspect();   // Okay: doesn't change a changeable object
  changeable.mutate();    // Okay: changes a changeable object
  unchangeable.inspect(); // Okay: doesn't change an unchangeable object
  unchangeable.mutate();  // ERROR: attempt to change unchangeable object
}

The attempt to call unchangeable.mutate() is an error caught at compile time. There is no runtime space or speed penalty for const, and you don’t need to write test-cases to check it at runtime.

The trailing const on inspect() member function should be used to mean the method won’t change the object’s abstract (client-visible) state. That is slightly different from saying the method won’t change the “raw bits” of the object’s struct. C++ compilers aren’t allowed to take the “bitwise” interpretation unless they can solve the aliasing problem, which normally can’t be solved (i.e., a non-const alias could exist which could modify the state of the object). Another (important) insight from this aliasing issue: pointing at an object with a pointer-to-const doesn’t guarantee that the object won’t change; it merely promises that the object won’t change via that pointer.

Scant answered 20/3, 2020 at 19:44 Comment(0)
A
0

In const objects only const methods can be called. All fielnd in such a method considered as const field. Last issue has curious effect:

  • pointer becomes a const pointer int* const, which is not the same as a pointer to const const int*. Thus you can alter the object which pointer points to, but can't make pointer to point to another object.
  • reference should become a const reference, but it is invariantly a const reference: you can not re-init it to another object. But again you can alter the object which reference refers to.
Alannaalano answered 14/12, 2021 at 15:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.