Considérez l'extrait de code suivant:
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();
}
Ici, je m'attends à ce que le compilateur échoue à la compilation par manque de constance pour appeler A::nonConstFun()
à l'intérieur B::fun()
quel que soit le type d'objet A.
Cependant, le compilateur se plaint pour l'objet, mais pas pour le pointeur. Pourquoi? J'utilise VS2017 sur Windows 10.
Il est appliqué.
Si vous essayez de changer le pointeur, le compilateur ne vous le permettra pas.
La chose vers laquelle pointe le pointeur, cependant, est une conversation différente.
Rappelles toi, T* const
et T const*
ce n'est pas la même chose!
Vous pouvez protéger cela en le faisant réellement A const*
, ou simplement en écrivant votre fonction de la manière appropriée.
Les autres réponses expliquent le T* const
contre T const *
c'est ce qui se passe. Mais il est important de comprendre l'implication de cela au-delà de la simple syntaxe.
Lorsque vous avez un T*
à l'intérieur d'une structure, le pointeur est à l'intérieur de l'objet, mais l'objet pointé est physiquement à l'extérieur de la structure. C'est pourquoi pour un objet const avec un T*
membre, il n'est pas autorisé à modifier le pointeur, mais il est autorisé à modifier l'objet pointé - car physiquement l'objet pointé est en dehors de l'objet englobant.
Et c'est au programmeur de décider si l'objet pointé fait logiquement partie de l'objet englobant (et en tant que tel doit partager la constance avec l'enveloppe) ou s'il s'agit logiquement d'une entité externe.
Le défaut de C++ est qu'il n'offre pas un moyen facile d'exprimer une constance logique comme indiqué ci-dessus (ce que vous attendiez réellement de votre code).
Ceci est connu et dans ce but précis, il existe une classe expérimentale qui n'est pas encore standard propagate_const
std :: experimental :: propagate_const est un wrapper de propagation const pour les pointeurs et les objets de type pointeur. Il traite le pointeur encapsulé comme un pointeur vers const lorsqu'il est accessible via un chemin d'accès const, d'où le nom.
struct B
{
A a_;
std::experimental::propagate_const<A *> pA_;
void fun()
{
pA_->nonConstFun(); // OK
}
void fun() const
{
// pA_->nonConstFun(); // compilation error
}
};