Чому функція-член const може змінити статичний член даних?


86

У наступній C++програмі зміна статичного елемента даних із constфункції працює нормально:

class A 
{
  public:   
    static int a; // static data member

    void set() const
    {
        a = 10;
    }
};

Але модифікація нестатичного члена даних із constфункції не працює:

class A 
{
  public:   
    int a; // non-static data member

    void set() const
    {
        a = 10;
    }
};

Чому constфункція-член може змінювати staticелемент даних?


Було б корисно, якби ви могли сказати нам, з якою платформою та компілятором ви працюєте? Тож ми можемо визначити, чи є поведінка помилкою, пов’язаною з вашими конкретними налаштуваннями, чи дійсно поведінка є правильною і її просто потрібно пояснити.
Alex Zywicki,

@AlexZywicki G ++ компілятор на платформі Linux.
msc

8
Нема потреби. Це навмисно, і всі компілятори C ++ повинні це підтримувати. Але чому такі добрі питання більше не проголосують?
Вірсавія

18
Це обман, але він написаний краще, ніж інший, завдяки кращому MCVE, тому я використав це як ціль.
Baum mit Augen

5
Мотивація тут полягає в тому, що constозначає, що функція-член об’єкта не може змінити цей об’єкт . Він може модифікувати інші об'єкти того самого класу або staticдані, які пов'язані з класом, а не будь-який його конкретний екземпляр. (Або mutableчлени даних, які були створені як виняток із цього правила.)
Девіслор,

Відповіді:


100

Це правило, ось і все. І недарма.

constКласифікатор на функції члена означає , що ви не можете змінити непро- mutableнепро- staticзмінних - членів класу.

Запропонуючи деяку раціоналізацію, thisпокажчик у constкваліфікованій функції-члена є constтипом і thisза своєю суттю пов'язаний з екземпляром класу. staticчлени не пов'язані з екземпляром класу. Вам не потрібен екземпляр для зміни staticучасника: у вашому випадку ви можете це зробити, написавши A::a = 10;.

Отже, у вашому першому випадку думайте про a = 10;скорочення, A::a = 10;а у другому - про скорочення this->a = 10;, яке не піддається компіляції, оскільки тип thisє const A*.


1
Тільки невелика помилка тут: Оскільки ви не можете перепризначити thisпокажчик, це буде тип типу const A* const у constвипадку.
Тейлор Хансен,

2
@TaylorHansen this- це перше значення покажчика. Prvalues ​​некласових типів ніколи не підлягають CV-кваліфікації.

21

Відповідно до стандарту C ++ (9.2.3.2 Статичні дані)

1 Статичний елемент даних не є частиною підпроектів класу ...

І (9.2.2.1 Цей покажчик)

1 У тілі нестатичної (9.2.1) функції-члена ключове слово this є виразом prvalue, значення якого є адресою об'єкта, для якого функція викликається. Тип цього у функції-члена класу X - X *. Якщо функція-член оголошена const, типом цього є const X * , ...

І нарешті (9.2.2 Нестатичні функції-члени)

3 ... якщо пошук імен (3.4) вирішує ім'я у виразі id на нестатичний нетиповий член якогось класу C, і якщо або вираз id потенційно обчислюється, або C є X або базовим класом X, вираз id перетворюється у вираз доступу до члена класу (5.2.5), використовуючи (* this) (9.2.2.1) як вираз постфіксу зліва від. оператора.

Таким чином, у цьому класі визначення

class A 
{
  public:   
    static int a; 

    void set() const
    {
        a = 10;
    }
};

член статичних даних aне є підпроектом об'єкта типу класу, і вказівник thisне використовується для доступу до статичного елемента даних. Отже, будь-яка функція-член, нестатична константа або непостійна, або статична функція-член може змінити елемент даних, оскільки вона не є константою.

У цьому класі визначення

class A 
{
  public:   
    int a; 

    void set() const
    {
        a = 10;
    }
};

нестатичний член даних aє подоб'єктом об'єкта типу класу. Для доступу до нього у функції-члена використовується або передбачається синтаксис доступу члена цього синтаксису. Ви не можете використовувати постійний вказівник thisдля зміни елемента даних. І покажчик, який це справді, має тип const A *усередині функції, setоскільки функція оголошена за допомогою кваліфікатора const. Якщо у функції не було кваліфікатора, в цьому випадку член даних можна було б змінити.


13

Річ у тім, що якщо функцією-членом класу Aє const, то тип thisє const X*і тим самим запобігає зміні нестатичних членів даних (пор., Наприклад, стандарт C ++ ):

9.3.2 Покажчик this [class.this]

В тілі нестатичної (9.3) функції-члена ключове слово this є виразом prvalue, значення якого є адресою об'єкта, для якого функція викликається. Тип цього у функції-члена класу X - X *. Якщо функція-член оголошена const, типом цього є const X *, ...

Якщо aє нестатичним членом даних, тоді a=10це те саме this->a = 10, що не допускається, якщо тип thisє const A*і aне був оголошений як mutable. Таким чином, оскільки void set() constробить тип thisістоти const A*, цей доступ заборонений.

Якщо aє статичним членом даних, навпаки, тоді a=10взагалі не бере участі this; і до тих пір, поки static int aсама по собі не була оголошена такою const, заява a=10допускається.


1

constВідбірковий на велічінуХі функції члена означає , що ви не можете змінити non-mutable, non-static член класу .

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