你混淆了两种情况:
虽然形式上(在计算机科学理论中)这两者都处理子类化,但实际情况是它们的 C++ 规则是不同的,因为const T
and的表示T
保证是相同的,而Base*
and的表示Derived*
通常相差一个偏移量(但在涉及虚拟继承时可能完全不同)。
在 3.9.3 中,标准声明
类型的cv 限定或cv 非限定版本是不同的类型;但是,它们应具有相同的表示和对齐要求
鉴于:
struct Base {};
struct Derived : Base {};
Derived* pd = nullptr;
Base* pb = pd;
const
确实可以按照您建议的方式添加。
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
Derived*
但是和之间没有 is-a 关系Base*
。存在转换,但Derived*
变量不一定包含对象的地址Base
(Base
对象内的子Derived
对象可能有不同的地址)。因此,您抱怨的那一行和您认为有效的那一行都是非法的:
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
正式地,该标准在 4.10 中对此进行了描述:
“指向 cv 的指针D
”类型的纯右值,其中D
是类类型,可以转换为“指向 cv 的指针B
”类型的纯右值,其中B
是 的基类D
。如果B
是 的不可访问或不明确的基类D
,则程序必须进行这种转换是格式错误的。转换的结果是指向派生类对象的基类子对象的指针。空指针值转换为目标类型的空指针值。
转换的结果是一个纯右值,它没有地址,你不能创建指向它的指针。