Reputation: 21773
Please read my question before linking parashift, I can google search, this is slightly different case.
This isn't allowed
Child **cc;
Base ** bb = cc;
Because you could do
*bb = new OtherChild;
But if we have
Child **cc;
const Base *const *const bb = cc;
I don't think all those const are necessary for my example, but just to be sure..
I think the minimum which should work is
Base *const *bb = cc;
Then you can't do this
*bb = new OtherChild;
So it should be safe. But why isn't it allowed?
Upvotes: 9
Views: 614
Reputation: 283634
You're confusing two cases:
const
While formally (in computer science theory) both of these deal with subclassing, the reality is that the C++ rules for these are different, because the representation of const T
and T
are guaranteed to be the same, while the representations of Base*
and Derived*
often differ by an offset (but may be radically different when virtual inheritance is involved).
In 3.9.3, the Standard declares that
The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same representation and alignment requirements
Given:
struct Base {};
struct Derived : Base {};
Derived* pd = nullptr;
Base* pb = pd;
const
can indeed by added in the way you suggest.
Base const* const* const cpcpcb = &pb;
Base* const* pcpb = &pb; // legal, pointer can't be changed
Base const* * ppcb = &pb; // illegal, one could try to rebind the pointer
// to a truly const object, then
// use pb to mutate the const object
But there is no is-a relationship between Derived*
and Base*
. A conversion exists, but the Derived*
variable does not necessarily contain the address of a Base
object (the Base
subobject within the Derived
object may have a different address). And therefore both the line you're complaining about, and the line your question assumed was valid, are illegal:
Base const* const* const cpcpcd = &pd; // error, there's no address of a Base
// to be found in pd
Base* const* pcpd = &pd; // error: again, there's no address of a Base
// stored in pd
Formally, the Standard describes this in 4.10:
A prvalue of type "pointer to cv
D
”, whereD
is a class type, can be converted to a prvalue of type "pointer to cvB
", whereB
is a base class ofD
. IfB
is an inaccessible or ambiguous base class ofD
, a program that necessitates this conversion is ill-formed. The result of the conversion is a pointer to the base class subobject of the derived class object. The null pointer value is converted to the null pointer value of the destination type.
The result of the conversion is a prvalue, it doesn't have an address, and you can't create a pointer to it.
Upvotes: 6
Reputation: 70392
This is a constraint imposed by the C++ language, because implicit conversion of pointer types is based on inheritance rules (with the exception of implicit conversion to void *
).
That is, given the following program, the assignment is only allowed if T
is a base of U
:
T const *x;
U *y;
x = y;
However, in your case:
typedef Base *T;
typedef Child *U;
The relationship between Base
and Child
does not transfer to their pointer types. So, there is no inheritance relationship between "pointer to Base
" and "pointer to Child
" to allow the direct assignment you desire.
Upvotes: 1
Reputation: 9801
I think that in your equation you are expecting const
to play a bigger role than what it really has.
const
is a qualifier, and simply put, its role is to regulate the way you access a type or a variable.
The main point is if the language itself, without even considering what is const
or not, already regulates a given behaviour, your specific case is not that different from the one reported by that FAQ.
You are in a really simple situation, and you should probably think in much simpler terms.
Upvotes: 0