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

620

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

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};
Теги:
const
declaration
c++-faq

8 ответов

786

Когда вы добавляете ключевое слово 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

В методе non-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 << "The MyClass instance has been invoked " << ccc.GetInvocations() << " times" << endl;
}

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

Foo
Foo const
The MyClass instance has been invoked 2 times
180

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

const foobar fb;
fb.foo();

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

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

39

Квалификатор 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);
  • 2
    Я думал, что ответ о других методах const, а не об объектах const.
  • 0
    Спасибо за «Идея, лежащая в основе const заключается в том, чтобы маркировать методы, которые не изменят внутреннее состояние класса». Это действительно то, что я искал.
Показать ещё 1 комментарий
21

Эти константы означают, что компилятор будет 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
}

Подробнее о

  • 1
    Вопрос о const функциях-членах, которые не упоминают mutable, в лучшем случае неполон.
9

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

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

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

6

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

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

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

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

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

0

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

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
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню