C++ 复杂的动态c++;
我用C++编写了以下案例:C++ 复杂的动态c++;,c++,polymorphism,language-lawyer,dynamic-cast,cross-cast,C++,Polymorphism,Language Lawyer,Dynamic Cast,Cross Cast,我用C++编写了以下案例: 抽象基类Abstract1和Abstract2。他们没有关系 源于Abstract1和Abstract2 我在一个编译单元中,没有关于类Foo(没有声明,没有定义)的信息。只有Abstract1和Abstract2是已知的。 (实际上,Foo甚至是在DLL中定义的) 动态强制转换是否允许从Abstract1*强制转换到Abstract2*?这是标准吗?是的,它会起作用 dynamic_cast基于。RTTI在此提供的信息足以确定指向对象的实际动态类型。根据定义,R
- 抽象基类
和Abstract1
。他们没有关系Abstract2
- 源于
和Abstract1
Abstract2
Foo
(没有声明,没有定义)的信息。只有Abstract1
和Abstract2
是已知的。
(实际上,Foo甚至是在DLL中定义的)
动态强制转换是否允许从Abstract1*
强制转换到Abstract2*
?这是标准吗?是的,它会起作用
dynamic_cast
基于。RTTI在此提供的信息足以确定指向对象的实际动态类型。根据定义,RTTI是一个运行时概念,指向对象的动态类型也是如此(编写所述cast的编译单元中没有Foo的定义这一事实是一个编译时概念,与此无关)
- 如果指向的对象实际上是一个Foo,则动态\u转换将在运行时成功
- 如果它不是指向从Abstract2派生的对象的指针,它将失败(返回空指针)
dynamic_cast
的一个可能实现是在对象内存布局的开始处查找一个特殊成员(或者它可以存储在v表中)。此结构可以包含一个值,该值标识对象的动态类型。
在某个地方,编译器会生成一个静态表,复制有关程序继承图的所有信息。
在运行时,cast将提取实例的类型标识符,并对照静态表进行检查。如果此标识符引用从Abstract2派生的类型,则强制转换是有意义的(并且代码可以返回一个指向对象的Abstract2
接口的指针)
即使是这种幼稚的实现也不需要编译单元中的Foo
知识
cast是书面的。您描述的是所谓的交叉cast。对于
dynamic\u cast(v)
,标准在[expr.dynamic.cast]/8中规定
如果C
是T
指向或引用的类类型,则运行时
检查逻辑上执行如下操作:
- 如果在
指向(引用)的最派生对象中,v
指向(引用)一个v
对象[…]的公共基类子对象C
- 否则,如果
指向(引用)最派生对象的v
基类子对象,以及最派生对象的类型 有一个类型为公共
的基类,该基类是明确的,C
结果点(指)是最派生的public
子对象 对象。C
Foo
存在的信息,这也会起作用你也应该去看看。好吧,你可以试一下
#包括
结构IBase1
{
虚拟void foo()=0;
虚拟~IBase1(){}
};
结构IBase2
{
虚拟空心条()=0;
虚拟~IBase2(){}
};
派生结构:IBase1、IBase2
{
void foo(){}
无效条(){}
};
int main()
{
导出d;
IBase1*ptr=&d;
断言(动态_cast(ptr));
断言(动态_cast(ptr));
}
//编译成功
这就是证据:
[C++11:5.2.7/8]:
如果C
是T
指向或引用的类类型,则运行时检查按如下逻辑执行:
- 如果在由
指向(引用)的最派生对象中,v
指向(引用)一个v
对象的C
基类子对象,并且如果从由public
指向(引用)的子对象仅派生一个v
类型的对象,则结果点(引用)到C
对象C
- 否则,如果
指向(引用)最派生对象的公共基类子对象,并且最派生对象的类型具有类型为v
的基类,即明确且C
,则结果指向(引用)到最派生对象的public
子对象。C
- 否则,运行时检查将失败
该语言没有规定“当前”翻译单元中已知最派生对象的类型;这取决于实现,在常见的“虚拟表”模型中,确实如此。对于此代码:
void func(Abstract1* a1)
{
Abstract2* a2 = dynamic_cast<Abstract2*>(a1);
...
}
void func(抽象1*a1)
{
Abstract2*a2=动态铸型(a1);
...
}
你在问:
void func(Abstract1* a1)
{
Abstract2* a2 = dynamic_cast<Abstract2*>(a1);
...
}
如果a1
指向Foo
对象,动态强制转换是否会返回有效的对象指针
答案是肯定的:
void func(Abstract1* a1)
{
Abstract2* a2 = dynamic_cast<Abstract2*>(a1);
...
}
- 在运行期间,动态强制转换将
的V-Table标识为a1
的V-Table类Foo
- 由于
继承自class Foo
,因此动态强制转换将返回有效指针class Abstract2
Foo
的定义在转换点不可用。@NeilKirk这不是必需的。没有理由这么做。@NeilKirk:不要紧,一些有效的东西可能只是未定义的行为。尝试不会带来任何好处proof@galinette:这就是为什么我的答案以标准文本结尾。@galinette:我不知道你在说什么!;)