9

请在链接 parashift 之前阅读我的问题,我可以谷歌搜索,情况略有不同。

这是不允许的

Child **cc;
Base ** bb = cc;

因为你可以

*bb = new OtherChild;

但是如果我们有

Child **cc;
const Base *const *const bb = cc;

我不认为所有这些 const 对于我的示例都是必需的,但只是为了确定..

我认为应该工作的最低限度是

Base *const *bb = cc;

那么你不能这样做

*bb = new OtherChild;

所以应该是安全的。但是为什么不允许呢?

4

3 回答 3

6

你混淆了两种情况:

  • 添加的const
  • 向上转型

虽然形式上(在计算机科学理论中)这两者都处理子类化,但实际情况是它们的 C++ 规则是不同的,因为const Tand的表示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*变量不一定包含对象的地址BaseBase对象内的子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,则程序必须进行这种转换是格式错误的。转换的结果是指向派生类对象的基类子对象的指针。空指针值转换为目标类型的空指针值。

转换的结果是一个纯右值,它没有地址,你不能创建指向它的指针。

于 2013-08-17T04:22:58.487 回答
1

这是 C++ 语言强加的约束,因为指针类型的隐式转换基于继承规则(隐式转换为 除外void *)。

也就是说,给定以下程序,仅当T是 的基数时才允许赋值U

T const *x;
U *y;
x = y;

但是,在您的情况下:

typedef Base *T;
typedef Child *U;

Base和之间的关系Child不转移到它们的指针类型。Base因此,“pointer to ”和“pointer to ”之间没有继承关系,Child可以直接赋值。

于 2013-08-17T02:54:01.620 回答
0

我认为在你的方程式中,你期望const发挥比它真正拥有的更大的作用。

const是一个限定符,简单地说,它的作用是规范你访问一个类型或一个变量的方式。

主要的一点是,如果语言本身,甚至不考虑什么是const或不是,已经规范了给定的行为,那么您的具体情况与该常见问题解答报告的情况没有什么不同。

你处于一个非常简单的情况,你可能应该用更简单的术语来思考。

于 2013-08-07T12:04:40.750 回答