Because converting Foo**
→ const Foo**
would be invalid and dangerous.
C++ allows the (safe) conversion Foo*
→ Foo const*
, but gives an error if you try to implicitly convert Foo**
→ const Foo**
.
The rationale for why that error is a good thing is given below. But first, here is the most common solution: simply change const Foo**
to const Foo* const*
:
class Foo { /* ... */ };
void f(const Foo** p);
void g(const Foo* const* p);
int main()
{
Foo** p = /*...*/;
// ...
f(p); // ERROR: it‘s illegal and immoral to convert Foo** to const Foo**
g(p); // Okay: it‘s legal and moral to convert Foo** to const Foo* const*
// ...
}
The reason the conversion from Foo**
→ const Foo**
is dangerous is that it would let you silently and accidentally modify a const Foo
object without a cast:
class Foo {
public:
void modify(); // make some modification to the this object
};
int main()
{
const Foo x;
Foo* p;
const Foo** q = &p; // q now points to p; this is (fortunately!) an error
*q = &x; // p now points to x
p->modify(); // Ouch: modifies a const Foo!!
// ...
}
If the q = &p
line were legal, q
would be pointing at p
. The next line, *q = &x
, changes p
itself (since *q
is p
) to point at x
. That would be a bad thing, since we would have lost the const
qualifier: p
is a Foo*
but x
is a const Foo
. The p->modify()
line exploits p
’s ability to modify its referent, which is the real problem, since we ended up modifying a const Foo
.
By way of analogy, if you hide a criminal under a lawful disguise, he can then exploit the trust given to that disguise. That’s bad.