Почему константа не применяется для указателей?

Рассмотрим следующий фрагмент кода:

class A
{
public:

    void nonConstFun()
    {

    }
};

class B
{
private:

    A a_;
    A * pA_;

public:

    void fun() const
    {
        pA_->nonConstFun();
        //a_.nonConstFun(); // Gives const related error
    }
};

int main()
{
    B b;
    b.fun();
}

Здесь я ожидаю, что компилятор завершит компиляцию из-за отсутствия константы для вызова A::nonConstFun() внутри B::fun() независимо от типа объекта A.

Однако компилятор жалуется на объект, но не на указатель. Зачем? Я использую VS2017 в Windows 10.

Ответ 1

Он применяется.

Если вы попытаетесь изменить указатель, компилятор не позволит вам.

Тем не менее, указывает указатель на другой разговор.

Помните, что T* const и T const* - это не одно и то же!

Вы можете защитить это, либо сделав его A const*, либо просто написав свою функцию таким образом, который подходит.

Ответ 2

Другие ответы объясняют T* const vs T const * что и происходит. Но важно понимать, что это означает не только простой синтаксис.

Когда у вас есть T* внутри структуры, указатель находится внутри объекта, но указанный объект физически находится за пределами структуры. Поэтому для объекта const с членом T* не разрешается изменять указатель, но ему разрешено изменять заостренный объект, потому что физически заостренный объект находится за пределами объекта-объекта.

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

Недостаток C++ заключается в том, что он не предлагает простой способ выразить логическую константу, как указано выше (что вы действительно ожидали от своего кода).

Это известно и для этой точной цели есть экспериментальный класс, который еще не является стандартом propagate_const

std :: experimental :: propagate_const - это const-распространяющая оболочка для указателей и указательных объектов. Он обрабатывает завернутый указатель как указатель на const при доступе через путь доступа к const, отсюда и название.

struct B
{
    A a_;
    std::experimental::propagate_const<A *> pA_;

   void fun()
    {
        pA_->nonConstFun(); // OK
    }
    void fun() const
    {
        // pA_->nonConstFun(); // compilation error
    }
};