次のコードスニペットを検討してください。
_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オブジェクトのタイプに関係なく、A::nonConstFun()
をB::fun()
内で呼び出すための定数がないために、コンパイラがコンパイルに失敗することを期待しています。
ただし、コンパイラーはオブジェクトに対して文句を言いますが、ポインターに対しては文句を言いません。どうして? Windows 10でVS2017を使用しています。
It is強制されます。
ポインタを変更しようとすると、コンパイラは許可しません。
ただし、ポインターが指すのは別の会話です。
覚えておいて、T* const
およびT const*
は同じものではありません!
あなたはそれを実際に作ることによってそれを保護することができますA const*
、または単に適切な方法で関数を記述することによって。
他の回答では、T* const
対T const *
について説明しています。しかし、単なる構文を超えてこれの意味を理解することが重要です。
構造体内にT*
がある場合、ポインターはオブジェクト内にありますが、ポイントされたオブジェクトは物理的に構造体の外にあります。 T*
メンバーを持つconstオブジェクトの場合、ポインターを変更することはできませんが、ポイントされたオブジェクトを変更することはできます。
そして、先のとがったオブジェクトが論理的に囲んでいるオブジェクトの一部であるかどうかを決定するのはプログラマー次第です(したがって、囲んでいるオブジェクトとconstnessを共有する必要があります)または論理的に外部エンティティである場合。
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
}
};