5.2.7 (ISO/IEC 14882, 12/29/2003) 在这一点上非常明确:
[关于表达dynamic_cast<T>(v)
]
如果T
是“指向cv1 B
的指针”并且v
具有类型“指向cv2
D
的指针”,它B
是 的基类D
,则结果是指向 指向的对象的唯一子B
对象的指针。[... bla bla about cv1 和 cv2 ...]和 B 应该是 D 的可访问的明确基类(强调我的)D
v
(回忆 11.2 “如果基类的一个发明的公共成员是可访问的,则称该基类是可访问的。”)。
这就解释了为什么第一个演员表有效。现在,对于第二个:
[...]
否则,将应用运行时检查以查看是否v
可以将指向或引用的对象转换为指向或引用的类型T
。
运行时检查在逻辑上执行如下:
- 如果在由 指向(引用)的最派生对象中
v
,v
指向(引用)一个对象的public
基类子T
对象,并且如果只有一个 T 类型的对象从由 指向(引用)的子对象派生v
,则result 是指向该T
对象的指针(左值引用)。
- 否则,如果
v
指向(引用)最派生对象的public
基类子对象,并且最派生对象的类型具有类型为 的基类,该基类T
是明确的并且public
,则结果是一个指针(一个左值引用) 到T
最派生对象的子对象。
- 否则,运行时检查将失败。
转换为指针类型失败的值是所需结果类型的空指针值。转换为引用类型失败会抛出 bad_cast (18.5.2)。
因此,您观察到的行为似乎是由于private
继承:即使基类是可访问的,它也不是public,并且标准要求public,不可访问。
烦人,不是吗?我手边没有 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 限定或大于 cv1 的 cv 限定,并且 B 不是 D 的虚拟基类。空指针value (4.10) 被转换为目标类型的空指针值。如果“指向 cv1 B 的指针”类型的右值指向实际上是 D 类型对象的子对象的 B,则生成的指针指向 D 类型的封闭对象。否则,强制转换的结果是未定义的.
所以如果你确定指针的实际动态类型是什么,你就可以进入static_cast
inside foo
。
我会对有关为什么存在这种不一致的任何其他信息感兴趣。