私有范围内私有继承的动态下转

Ziv*_*Ziv 18 c++ casting private downcast

我已经遇到过这个问题的调整.考虑:

class A {};

class B : private A {
   static void foo();
};

void B::foo(){
   B* bPtr1 = new B;
   A* aPtr1 = dynamic_cast<A*>(bPtr1); // gives pointer
   B* bPtr2 = dynamic_cast<B*>(aPtr1); // gives NULL
}
Run Code Online (Sandbox Code Playgroud)

aPtr1事实上,因为它是类型的B*,并且因为我们已经完全访问B并继承了它A,所以我希望两个转换都可以工作.但他们没有; 为什么?还有另一种方法来实现这种演员吗?

注意:

  • 如果foo()不是B的成员,两个演员都会失败.
  • 如果BA公开继承,两个演员都可以.

Ale*_* C. 16

5.2.7(ISO/IEC 14882,12/29/2003)在这一点上非常明确:

[关于表达dynamic_cast<T>(v)]

如果T是"指向cv1的 指针B"并且v具有类型"指向cv2的 指针D",这B是一个基类D,则结果是指向由其指向BD对象的唯一子对象的指针v.[... bla bla about cv1 and cv2 ...] 和B将是一个可访问的明确基类D (强调我的)

(回想11.2 "如果可以访问基类的发明公共成员,则可以访问基类.").

这解释了为什么第一个演员工作.现在,第二个:

[...]

否则,将应用运行时检查以查看指向或引用的对象是否v可以转换为指向或引用的类型T.

运行时检查在逻辑上执行如下:

  • 如果,在指向(引用)的最多派生对象中v,v指向(引用)public对象的基类子T对象,并且如果只有一个对象类型T是从指向(引用)的子对象派生的v,则result是指向该T 对象的指针(左值引用).
  • 否则,如果vpoint(引用)到public最派生对象的基类子对象,并且最派生对象的类型具有类型的基类T,那是明确的public,结果是指针(左值引用) )到T最派生对象的子对象.
  • 否则,运行时检查失败.

失败的强制转换为指针类型的值是所需结果类型的空指针值.失败的强制转换为引用类型会抛出bad_cast(18.5.2).

因此,您观察到的行为似乎是由于private继承:即使基类可访问,它也不公开,标准需要公共,不可访问.

烦人,不是吗?我没有方便的C++ 0x草案,也许有人可以用引号来编辑我的答案,万一事情发生了变化.

还有另一种方法来实现这种演员吗?

这取决于你想做什么.基本上,私有继承只是执行组合的另一种设备.如果您确实要返回指向私有派生实例的指针,那么要么继承公共,要么返回成员.

无论如何,你会很高兴知道static_cast似乎没有这个限制:

5.2.9.[关于static_cast<T>(v)] [...]

类型为"指向cv1 B的指针"的左值,其中B是类类型,可以转换为"指向cv2 D的指针"类型的右值,其中D是来自B的派生类(第10节),如果是有效标准从"指向D的指针"到"指向B的指针"的转换存在(4.10),cv2与cv1相同,或者cv-qualification更高,cv1和B不是D的虚基类.空指针value(4.10)将转换为目标类型的空指针值.如果类型"指向cv1 B的指针"的rvalue指向实际上是D类型对象的子对象的B,则生成的指针指向类型D的封闭对象.否则,转换的结果是未定义的.

因此,如果您确切知道指针的实际动态类型是什么,则允许您进入static_cast内部foo.

我对有关为何存在这种不一致的任何其他信息感兴趣.