考虑一下场景:
class Base { };
class Derived: public virtual Base {};
int main(void) {
Derived * d = new Derived();
Base * b = d;
Derived * x = static_cast<Derived*>(b); // Probably impossible
delete x;
}
Run Code Online (Sandbox Code Playgroud)
这里从指向Base到指向Derived的指针的向下转换给出了一个编译错误,说"由于base是虚拟的,因此无法转换".我不能动态转换,因为Base不是多态类型.我的问题是:
如果不可能,我想了解原因.我知道虚拟方法是通过vptr表实现的,但是如何实现虚拟基类?我也知道C++标准没有定义实现,但我想了解像gcc这样常见的东西的实现.所以问题是:
对于那里的所有C++专家来说,这可能是一个相当简单的问题,但是在google-ing半小时之后我找不到具体的东西.如果已经涵盖,请随意复制,投票等.
这根本不可能吗?
是.
C++标准(11或14)如何表明这是不可能的?
根据要求说明static_cast.
[expr.static.cast] - 强调我的
11型"指针CV1 B",其中B是一个类型,可被转化为式的prvalue的prvalue"指针CV2 d",其中d是从乙派生的类(第[class.derived]) ,如果一个有效的标准转换从"指针d"到"指针到B"的存在([conv.ptr]),CV2是相同的CV-资格,或更大的CV-资格比,CV1,和B既不是D的虚基类,也不是D的虚基类的基类.
如您所见,Base不能是虚拟甚至是另一个虚拟基础的非虚拟基础.
像gcc这样的标准编译器的底层实现是什么使得这个特性变得不可能?
虚拟继承是一种允许Base在不同的中间基类之间共享相同子对象的机制.例如,如果您要添加:
class Derived2: public virtual Base {};
class MostDerived: public Derived, public Derived2 {};
Run Code Online (Sandbox Code Playgroud)
然后MostDerived将有一个类型Derived和类型的子对象Derived2,但与常规继承不同,它们不会各自拥有自己的Base子对象(因此有2 Base个子对象MostDerived).取而代之的将只有一个Base子对象,两者Derived并Derived2会参考它.
这通常通过一些指针间接完成Derived并Derived2访问它Base.他们不能依赖它在某个偏移处放置在自己内部.它们的位置Base由最派生的对象决定.所以,如果你有一个Base*,那么就没有一种明确的方法可以找到Derived引用它的对象.
在非虚拟继承的情况下,Base它将位于编译器已知的相对于Derived完全包含它的子对象的位置.因此编译器可以执行获取Derived子对象所需的指针运算.但在你的情况下,它不能,因为不能保证相对位置.访问(通常)是间接访问.
你没有问,但我也可以解决这个问题.dynamic_cast适用于多态类的原因是多态类可以在其vtable中将RTTI与它们相关联(如果它们有一个).并且因为Base*它将指向MostDerived(或Derived)的vtable ,该dynamic_cast机制可以利用该表中编写的信息来弄清楚如何获得它所需的子对象.该表可以包含从任何一个子对象到任何其他子对象所需的所有偏移信息.并且因为它是最派生对象的表(在运行时),所以该信息是固定且可靠的.
| 归档时间: |
|
| 查看次数: |
235 次 |
| 最近记录: |