Значение 'const' последний в объявлении функции класса? - PullRequest
653 голосов
/ 15 апреля 2009

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

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

Ответы [ 8 ]

861 голосов
/ 15 апреля 2009

Когда вы добавляете ключевое слово 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 << "The MyClass instance has been invoked " << ccc.GetInvocations() << " times" << endl;
}

что бы вывести

Foo
Foo const
The MyClass instance has been invoked 2 times
175 голосов
/ 15 апреля 2009

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

const foobar fb;
fb.foo();

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

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

43 голосов
/ 15 апреля 2009

Спецификатор const означает, что методы могут быть вызваны для любого значения foobar. Разница возникает, когда вы рассматриваете вызов неконстантного метода для константного объекта. Подумайте, имеет ли ваш тип 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 заключается в том, чтобы пометить методы, которые не изменят внутреннее состояние класса. Это мощная концепция, но на самом деле не применяется в C ++. Это скорее обещание, чем гарантия. И тот, который часто ломается и легко ломается.

foobar& fbNonConst = const_cast<foobar&>(fb1);
22 голосов
/ 15 апреля 2009

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

Читать это для получения дополнительной информации

10 голосов
/ 15 апреля 2009

Блэр ответ на вопрос.

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

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

8 голосов
/ 14 марта 2017

Значение функции-члена 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;
};
6 голосов
/ 30 мая 2015

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

3 голосов
/ 26 марта 2019

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

Вы также можете сделать это 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
}

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

...