Значення "const" останнього у функційному оголошенні класу?


727

Який сенс constу таких деклараціях? constМене бентежить.

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

Відповіді:


951

Коли ви додасте 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++;    // 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;
}

які б вивели

Foo
Foo const
Foo has been invoked 2 times

187

Конст означає, що метод обіцяє не змінювати членів класу. Ви зможете виконати такі позначені члени об'єкта, навіть якщо сам об'єкт був позначений const:

const foobar fb;
fb.foo();

було б законним.

Подивіться, скільки і для чого використовується “const” в C ++? для отримання додаткової інформації.


47

В constозначає класифікатор , що методи можуть бути викликані на будь-яке значення foobar. Різниця виникає, коли ви розглядаєте виклик методу non-const об'єкту const. Подумайте, чи був у вашого foobarтипу таке додаткове декларація методу:

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

Метод bar()не const і до нього можна отримати лише значення, які не мають const.

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

3
Я думав, що відповідь стосується інших методів const, а не про const-об'єктів.
Микола Голубєв

Дякую за те, що " constХоч ідея хоч - позначити методи, які не змінять внутрішній стан класу". Це справді те, що я шукав.
ковач

1
@JaredPar це означає, що будь-яку функцію-члена, що представляє операцію лише для читання, слід позначати як const?
ковач

26

Ці const означають, що компілятор помилиться, якщо метод '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функції учасників, яке не згадує змінні , в кращому випадку є неповним.
Неочікуваний

13

Відповідь Блера знаходиться на позначці.

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

Ви можете скористатися цим (наприклад), якщо ви хочете, щоб об'єкт запам'ятав, скільки разів викликається певний метод, при цьому це не впливає на "логічну" стійкість цього методу.


10

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

Тип цього вказівника у функції non-const класу X є X * const. Тобто це постійний вказівник на неконстантний X (див. Const Pointers and Pointers to Const [7, 21]). Оскільки об'єкт, на який це посилається, не є const, він може бути модифікований. Тип цього у функції 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;
};

thisне є const. Причина, по якій його неможливо змінити, полягає в тому, що це перше значення.
Брайан

7

коли ви використовуєте constв підписі методу (як ваш сказав const char* foo() const;:), ви повідомляєте компілятору, на який вказувала пам'ять, thisне можна змінити цим методом (що fooтут).


6

Я хотів би додати наступний пункт.

Ви також можете зробити це 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
}

Сміливо вдосконалюйте відповідь. Я не експерт


1
*thisзавжди є значенням, навіть якщо функція члена відповідає кваліфікації rvalue і називається на rvalue. Приклад .
HolyBlackCat

1
Так, як я повинен покращити свою теперішню відповідь?
coder3101

Я маю на увазі, що написати в коментарі в блоці, що виправдовує поведінку
coder3101

Оновлено. Чи це нормально?
coder3101

2

СопзЬ ключове слово , яке використовується з функцією декларація уточнюється , що вона є функцією члена Const , і він буде не в змозі змінити елементи даних об'єкта.


1

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

Що таке " constфункція члена"?

Функція члена, яка інспектує (а не мутує) його об'єкт.

Функція- constчлен вказується constсуфіксом відразу після списку параметрів функції-члена. Функції членів із constсуфіксом називаються "функціями членів const" або "inspectors". Функції учасників без 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 ++ заборонено приймати "побітову" інтерпретацію, якщо вони не зможуть вирішити проблему зшивання, яку зазвичай неможливо вирішити (тобто може існувати псевдонім non-const, який міг би змінити стан об'єкта). Ще одне (важливе) розуміння цієї проблематики: вказівка ​​на об'єкт з покажчиком на const не гарантує, що об'єкт не зміниться; він просто обіцяє, що об'єкт не зміниться через цей покажчик .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.