C++ 中的复杂dynamic_cast
Complex dynamic_cast in c++
我在C++有以下情况:
- 抽象基类
Abstract1
和Abstract2
。它们是无关的。
从 Abstract1
和Abstract2
派生Foo
类
我在一个编译单元中,我没有关于类Foo
的信息(没有声明,没有定义)。只有Abstract1
和Abstract2
是已知的。(实际上,Foo甚至在DLL中定义)
dynamic_cast允许从Abstract1*
铸造到Abstract2*
吗?这是一个标准吗?
你描述的是所谓的交叉投射。对于dynamic_cast<T>(v)
,标准在 [expr.dynamic.cast]/8 中指定
如果
C
是T
指向或引用的类类型,则运行时 检查逻辑执行如下:
如果在
v
指向(引用)的最派生对象中,v
点(引用)到C
对象的公共基类子对象[..]否则,如果
v
指向(引用)派生最多的对象的public
基类子对象,以及派生最多的对象的类型 有一个基类,类型为C
,它是明确和public
的, 结果点(引用)到派生最多的子对象的C
子对象 对象。
即使没有关于Foo
在包含演员表的翻译单元中存在的信息,这也可以工作。
你也应该看看这个问题。
是的,它会起作用。
dynamic_cast
是基于RTTI的。RTTI在此处提供的信息足以确定指向对象的实际动态类型。根据定义,RTTI 是一个运行时概念,指向对象的动态类型也是如此(事实上,Foo 的定义在编写所述强制转换的编译单元中不可用,这是一个编译时概念,在这里无关紧要)。
- 如果指向的对象实际上是 Foo,则dynamic_cast将在运行时成功。
- 如果它不是指向从 Abstract2 派生的对象的指针,它将失败(返回空指针)。
详
dynamic_cast
的一个可能的实现是在对象的内存布局的开头查找一个特殊成员(或者它可以沿着向量表存储)。此结构可以包含一个值,该值标识对象的动态类型。在某个地方,编译器会生成一个静态表,复制有关程序继承图的所有信息。在运行时,强制转换将提取实例的类型标识符,并根据静态表进行检查。如果此标识符引用从 Abstract2 派生的类型,则强制转换是有意义的(并且代码可以返回指向对象Abstract2
接口的正确偏移量指针)。
即使是这种朴素的实现也不需要编译单元中的Foo
知识,其中演员表被写了。
对于此代码:
void func(Abstract1* a1)
{
Abstract2* a2 = dynamic_cast<Abstract2*>(a1);
...
}
你在问:
如果a1
指向Foo
对象,动态强制转换会返回有效的对象指针吗?
答案是肯定的:
- 在运行时,动态转换会将
a1
的 V-Table 标识为 V-Table ofclass Foo
。 - 由于
class Foo
继承自class Abstract2
,动态强制转换将返回一个有效的指针。
好吧,你可以简单地尝试一下!
#include <cassert>
struct IBase1
{
virtual void foo() = 0;
virtual ~IBase1() {}
};
struct IBase2
{
virtual void bar() = 0;
virtual ~IBase2() {}
};
struct Derived : IBase1, IBase2
{
void foo() {}
void bar() {}
};
int main()
{
Derived d;
IBase1* ptr = &d;
assert(dynamic_cast<IBase2*>(ptr));
assert(dynamic_cast<Derived*>(ptr));
}
// Compiles successfully
这是证据:
[C++11: 5.2.7/8]:
如果C
是T
指向或引用的类类型,则运行时检查按如下逻辑执行:如果在派生对象中
- ,
v
指向(引用)的最派生对象中,v
指向C
对象的public
基类子对象,并且如果只有一个类型为C
的对象从指向(引用)的子对象派生v
则结果点(引用)到该C
对象。否则,如果
v
指向(引用)派生最多的对象的公共基类子对象,并且派生最多的对象的类型具有类型为C
的基类,该基类明确且public
,则结果指向(引用)派生最多的对象的C
子对象。否则,运行时检查将失败。
通俗地说,我们称之为交叉转换。
语言没有规定在"当前"翻译单元中知道派生最多的对象的类型;由实现来使其工作,并且在常见的"虚拟表"模型中,确实如此。
- 如何理解C++标准N3337中的expr.const.cast子句8
- C++Cast运算符过载
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- C++类中的二维"dynamic"数组?
- 错误:"cast"未命名类型void setCastDescription(std::string
- 通过使用 const-cast 的非常量引用来延长临时的寿命
- "(void) cast"与功能有什么区别 "__attributes__"来沉默未使用的参数警告?
- protobuf in C++ with dynamic binding for google::protobuf::M
- 警告的原因是什么:"when type is in parentheses, array cannot have dynamic size"?
- C++:"Expected '(' for function-style cast or type construction"错误
- 为什么选择 g++ 给予者:"error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]"
- CUDA 错误:"dynamic initialization is not supported for __device__, __constant__ and __shared__ variabl
- Gtk+ g_signal_connect() 和 C++ lambda 会导致"invalid cast"错误
- 如何修复'The procedure entry point SDL_RWclose could not be located in the dynamic link library'
- Shared_ptr cast vs static_cast speed
- 在 iOS 上使用 Aruco 构建 OpenCV 时"Functional-style cast from id to double is not allowed"
- "The ordinal 344 could not be located in the dynamic link library"
- 覆盖 CAST 运算符(我认为它被称为向下转换)
- Dynamic Cast C++ Fail
- dynamic-cast-c++dynamic_cast错误处理