Ссылки и указатели в константных методах класса

Сразу оставлю ссылку, где задаётся примерно такой же вопрос, может быть будет кому полезно статья.

Вопрос по следующему коду:

#include <iostream>

using std::endl;
using std::cout;

struct S{

    char arr[10];
    
    const char& operator[](size_t index) const{

        return arr[index];
    }

};

struct C{
    
    int x = 12;
    
    int* z = &x;

    int& y = x;

    void foo() const{

        ++y;

        ++*z;
    }
};

int main(){
   
   const C c;

   c.foo(); 

   cout<<c.x<<endl;
        
}

В этом примере у нас есть 2 класса с константными методами, я хочу разобраться как работает константность в методах. Правильно ли я понимаю, что в случае класса S внутри константного метода константность накладывается именно на char и мы получаем const char и именно поэтому мы должны писать const char в возвращаемом типе данного метода, так как иначе сбросится константность.

Следующий вопрос: почему в структуре C у меня получается изменить константное поле const int c внутри константного метода через ссылку/указатель, разве это не UB??? Я пытаюсь понять логику константных методов, помогите, пожалуйста, прояснить ситуацию. Единственное объяснение, которое я здесь нашел - в константных методах константность распространяется как бы только на имена полей: то есть я не могу напрямую через обращение по именам менять поля, однако зависимости в виде наличия ссылок сохраняются.


Ответы (1 шт):

Автор решения: Harry

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

Во втором случае имеется косвенность, которая и мешает определиться. Кто знает, куда там во время выполнения указывают z и y? Ведь можно переписать код так, что они будут указывать не на x. Так что вы изменить не можете само значение z, а вот то, на что оно указывает...

Вот пример (все остальное остается, как у вас):

int main()
{
    int v = 1;
    C c{12,&v,v};
    c.foo();
    cout<<c.x<<endl;
    cout<<v<<endl;
}

Компилятор не настолько умен, чтобы суметь понять, куда указывает z и на что ссылается y...

"По-моему, так" (с) Пух

→ Ссылка