在C++中,将指向派生类实例的指针转换为实例的基类,是否会有任何运行时开销,还是在编译时解决?
如果有的话,转换操作中需要计算什么?
示例:
class Foo;
class Bar : public Foo;
Bar* y = new Bar;
Foo* x = (Foo*) y;
(我知道应该使用C++风格的转换,而且答案可能对它们也是一样的)
我知道我应该使用C++风格的转换,并且它们的答案可能相同。在C++中,将指向派生类实例的指针转换为实例的基类,是否会有任何运行时开销,还是在编译时解决?
如果有的话,转换操作中需要计算什么?
示例:
class Foo;
class Bar : public Foo;
Bar* y = new Bar;
Foo* x = (Foo*) y;
(我知道应该使用C++风格的转换,而且答案可能对它们也是一样的)
我知道我应该使用C++风格的转换,并且它们的答案可能相同。是的,尽管影响微乎其微。
在这种情况下,C风格的转换被解释为static_cast
,可能会产生指针调整。
struct Base {};
struct Derived: Base { virtual ~Derived(); } // note: introduced a virtual method
int main()
{
Derived derived;
Base* b = &derived;
Derived* d = (Derived*) b;
void* pb = b;
void* pd = d;
printf("%p %p", pb, pd);
return 0;
}
当基类子对象的对齐地址和派生对象不同时,就会发生这种开销,情况如下:
当然,通常指针调整被认为是可以忽略的,如果不需要调整(即调整为0),编译器应该足够聪明以消除它。
注意:这取决于具体实现,而不是标准规定
Foo* x = (Foo*) y;
Bar*
转换为Foo*
。从派生类到基类的转换是隐式的。Foo* x = y ; // is enough!
C语言的类型转换没有任何运行时开销。唯一会产生运行时开销的类型转换操作是 dynamic_cast<>()
,因为它需要检查运行时的类型信息。
dynamic_cast
可以跨越多重继承类层次结构进行转换。static_cast
只能在类层次结构中向上或向下转换。 - James McNellisC
派生自A
和B
,那么你不能做例如A *p = new C;
的操作吗? - Oliver CharlesworthDerived*
转换为Base*
(至少如果基类是可访问的)。此转换只向上强制转换继承层次结构。你不能这样做A* p; B* q = static_cast<B*>(p);
因为这会跨越层次结构进行类型转换。你需要使用一对static_cast
强制转换将A*
转换为C*
再转换为B*
。 - James McNellisint i = 42; (double)i;
也有开销,因为CPU必须将int
转换为double
。我认为在讨论强制类型转换时,“运行时开销”的通常含义是“需要某种类型查找”。 - James McNellis请参考类似问题的答案:regular cast vs static cast vs dynamic cast
总结:C风格转换不会引起运行时开销,因为它会尝试使用一些C++转换方法,除了dynamic_cast
(它会产生运行时开销)。