Значение 'const' является последним в объявлении функции класса?

В чем смысл const в таких объявлениях? const меня смущает.

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

Ответ 1

Когда вы добавляете ключевое слово const к методу, указатель this по существу становится указателем на объект const, и поэтому вы не можете изменить какие-либо данные члена. (Если вы не используете mutable, об этом позже).

Ключевое слово const является частью сигнатуры функции, что означает, что вы можете реализовать два одинаковых метода, один из которых вызывается, когда объектом является const, а другой - нет.

#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();
}

Это выведет

Foo
Foo const

В неконстантном методе вы можете изменить элементы экземпляра, чего нельзя сделать в версии const. Если вы измените объявление метода в приведенном выше примере на приведенный ниже код, вы получите несколько ошибок.

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

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

Это не совсем так, потому что вы можете пометить элемент как mutable, а метод const может изменить его. В основном используется для внутренних счетчиков и прочего. Решением для этого будет следующий код.

#include <iostream>

class MyClass
{
private:
    mutable int counter;
public:

    MyClass() : counter(0) {}

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

    void Foo() const
    {
        counter++;
        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" << endl;
}

который будет выводить

Foo
Foo const
Foo has been invoked 2 times

Ответ 2

Сопоставление означает, что метод promises не должен изменять каких-либо членов класса. Вы могли бы выполнить объекты, отмеченные таким образом, даже если сам объект был помечен const:

const foobar fb;
fb.foo();

будет законным.

См. Сколько и какие использует "const" в С++? для получения дополнительной информации.

Ответ 3

Квалификатор const означает, что методы могут быть вызваны при любом значении foobar. Разница возникает, когда вы рассматриваете вызов метода non-const для объекта const. Подумайте, имел ли ваш тип foobar следующее объявление дополнительного метода:

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

Метод bar() не является константой и может быть доступен только из неконстантных значений.

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

Идея const заключается в том, чтобы отметить методы, которые не изменят внутреннее состояние класса. Это мощная концепция, но на самом деле не реализуется в С++. Это скорее обещание, чем гарантия. И тот, который часто ломается и легко ломается.

foobar& fbNonConst = const_cast<foobar&>(fb1);

Ответ 4

Эти константы означают, что компилятор будет Error, если метод 'with const' изменяет внутренние данные.

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_;
};

Тест

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
}

Подробнее о

Ответ 5

Ответ Блэра находится на отметке.

Однако обратите внимание, что существует спецификатор mutable, который может быть добавлен к членам данных класса. Любой отмеченный таким образом член может быть изменен методом const без нарушения договора const.

Возможно, вы захотите использовать это (например), если хотите, чтобы объект запоминал, сколько раз вызывается какой-либо конкретный метод, не влияя на "логическую" константу этого метода.

Ответ 6

Значение функции-члена Const в C++ Общее знание: основное программирование на промежуточном уровне дает четкое объяснение:

Тип указателя this в неконстантной функции-члене класса X является X * const. То есть его постоянный указатель на непостоянный X (см. Const Указатели и Указатели на Const [7, 21]). Потому что объект к которому это относится, не является константой, его можно изменить. Тип это в const функция-член класса X является const X * const. Это является постоянным указателем на постоянную X. Поскольку объект Это относится к константам и не может быть изменено. Это Разница между константными и неконстантными функциями-членами.

Итак, в вашем коде:

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

Вы можете думать так:

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

Ответ 7

когда вы используете const в сигнатуре метода (например, ваш сказал: const char* foo() const;), вы сообщаете компилятору, что память, на которую указывает this, не может быть изменена этим методом (который foo здесь).

Ответ 8

Я хотел бы добавить следующее.

Вы также можете сделать это const & и const &&

Так,

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
}

Не стесняйтесь, чтобы улучшить ответ. Я не эксперт

Ответ 9

Ключевое слово const, используемое с объявлением функции, указывает, что это постоянная функция-член, и она не сможет изменять члены-данные объекта.

Ответ 10

Просто чтобы добавить ответ Матса Фредрикссона...

class MyClass {
    static int counter; // mutable (or static) allows const method to change it
public:
    void Foo()       {std::cout << "Foo "       << counter++ << std::endl;}
    void Foo() const {std::cout << "Foo const " << counter++ << std::endl;} // const obj calls this
};
int MyClass::counter = 0; // static counter needs initializing

int main() {
    MyClass a;
    const MyClass& b = a;
    a.Foo();
    b.Foo(); // calls const version
}