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

Каково значение const в объявлениях, подобных этим? const смущает меня

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

12 ответов

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

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

const foobar fb;
fb.foo();

было бы законно.

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

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);

Это 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
}

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

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

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

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

Значение функции-члена Const в C++. Общеизвестно: Essential Intermediate Programming дает четкое объяснение:

Тип указателя this в неконстантной функции-члене класса X - X * const. То есть это постоянный указатель на непостоянный X (см. Const Pointers и Pointers to Const [7, 21]). Поскольку объект, к которому это относится, не является константой, его можно изменить. Тип этого в функции-члене const класса X является const X * const. То есть это постоянный указатель на константу X. Поскольку объект, к которому это относится, является 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;
};

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

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

Здесь const означает, что в этой функции значение любой переменной не может измениться.

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

И, как в этом примере, если вы попытаетесь изменить значение переменной в тестовой функции, вы получите сообщение об ошибке.

СопзИте ключевое слово, используемое с функцией декларация уточняется, что она является функцией члена Const, и он будет не в состоянии изменить элементы данных объекта.

https://isocpp.org/wiki/faq/const-correctness

Что такое "const функция-член "?

Функция-член, которая проверяет (а не изменяет) свой объект.

А const функция-член обозначена constсуффикс сразу после списка параметров функции-члена. Функции-члены сconstсуффиксы называются "константными функциями-членами" или "инспекторами". Функции-члены безconst суффиксы называются "неконстантными функциями-членами" или "мутаторами".

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
}

Попытка позвонить unchangeable.mutate()это ошибка, обнаруженная во время компиляции. Нет места для времени выполнения или штрафа за скорость дляconst, и вам не нужно писать тестовые примеры, чтобы проверить это во время выполнения.

В конце const на inspect()Функция-член должна использоваться для обозначения того, что метод не изменяет абстрактное (видимое клиентом) состояние объекта. Это немного отличается от того, чтобы сказать, что метод не изменит "сырые биты" структуры объекта. Компиляторам C++ не разрешается использовать "побитовую" интерпретацию, если они не могут решить проблему сглаживания, которая обычно не может быть решена (то есть может существовать неконстантный псевдоним, который может изменять состояние объекта). Еще один (важный) вывод из этой проблемы псевдонима: указание на объект с помощью указателя на константу не гарантирует, что объект не изменится; он просто обещает, что объект не изменится с помощью этого указателя.

В объектах можно вызывать только методы. Все поле в таком методе рассматривается как constполе. Последний выпуск имеет любопытный эффект:

  • указатель становится константным указателем int* const, что не то же самое, что указатель на const const int*. Таким образом, вы можете изменить объект, на который указывает указатель, но не можете заставить указатель указывать на другой объект.
  • ссылка должна стать константной ссылкой, но это неизменно константная ссылка: вы не можете повторно инициализировать ее для другого объекта. Но опять же вы можете изменить объект, на который ссылается ссылка.
Другие вопросы по тегам