C++中的多态C风格转换是否有额外开销?

5
  • 在C++中,将指向派生类实例的指针转换为实例的基类,是否会有任何运行时开销,还是在编译时解决?

  • 如果有的话,转换操作中需要计算什么?

示例:

class Foo;
class Bar : public Foo;

Bar* y = new Bar;
Foo* x = (Foo*) y;

(我知道应该使用C++风格的转换,而且答案可能对它们也是一样的)

我知道我应该使用C++风格的转换,并且它们的答案可能相同。
4个回答

6

是的,尽管影响微乎其微。

在这种情况下,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),编译器应该足够聪明以消除它。

注意:这取决于具体实现,而不是标准规定


5
Foo* x = (Foo*) y;

不需要将Bar*转换为Foo*。从派生类到基类的转换是隐式的。
Foo* x = y ; // is enough!

关于多态转换,C风格的转换不等同于dynamic_cast。C++ dynamic_cast是一种全新的语言特性,与C风格的转换没有对应关系。
将指向派生类实例的指针转换为基类实例,在C++中会在编译时解决,如果像上面那样做。因此,它没有运行时开销。

这应该是一个注释。尽管如此,它并没有真正回答问题... - Oliver Charlesworth
@Nawaz:啊,好的 :) 无论如何,我会说可能会有一点开销:指针调整。不过偏移量应该在编译时就已知了... - Matthieu M.
@Matthieu:我们正在谈论“运行时”开销,而不是编译时。 :-) - Nawaz
@Nawaz:是的,非空偏移量意味着运行时计算(一个简单的加法/减法...但仍然需要计算!) - Matthieu M.
@Matthieu:你在说什么? - Nawaz
显示剩余6条评论

3

C语言的类型转换没有任何运行时开销。唯一会产生运行时开销的类型转换操作是 dynamic_cast<>(),因为它需要检查运行时的类型信息。


你确定在多重继承的情况下,这个说法(即“无运行时开销”)仍是正确的吗? - Oliver Charlesworth
@Oli:是的,因为只有dynamic_cast可以跨越多重继承类层次结构进行转换。static_cast只能在类层次结构中向上或向下转换。 - James McNellis
@James:我很少(基本上从不)使用MI。你是说如果C派生自AB,那么你不能做例如A *p = new C;的操作吗? - Oliver Charlesworth
@Oli:不,你可以这样做:你可以将Derived*转换为Base*(至少如果基类是可访问的)。此转换只向上强制转换继承层次结构。你不能这样做A* p; B* q = static_cast<B*>(p);因为这会跨越层次结构进行类型转换。你需要使用一对static_cast强制转换将A*转换为C*再转换为B* - James McNellis
1
@James:这正是我所想的!那么,我认为我的(暗示的)原始观点仍然成立:在多重继承中进行向上转型需要一小部分指针算术运算,因此并非零开销。 - Oliver Charlesworth
1
@Oli:哦,好的,是的,这取决于“开销”的定义。按照这个定义,即使是int i = 42; (double)i;也有开销,因为CPU必须将int转换为double。我认为在讨论强制类型转换时,“运行时开销”的通常含义是“需要某种类型查找”。 - James McNellis

1

请参考类似问题的答案:regular cast vs static cast vs dynamic cast

总结:C风格转换不会引起运行时开销,因为它会尝试使用一些C++转换方法,除了dynamic_cast(它会产生运行时开销)。


你的回答与大多数其他回答直接相矛盾,你能否澄清一下你的意思? - Richard Simons
犯了一个错误,抱歉 :) 更正了我的答案。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接