[英]function called by constructors of derived classes not supposed to be pure virtual in base class
[英]Virtual function performance when called by derived classes?
从编译时已知为派生类的类调用虚方法时是否存在性能损失? 下面我用派生类显式调用force_speak
。
码:
#include <iostream>
#include <array>
#include <memory>
class Base
{
public:
virtual void speak()
{
std::cout << "base" << std::endl;
}
};
class Derived1 : public Base
{
public:
void speak()
{
std::cout << "derived 1" << std::endl;
}
};
template<class B>
void force_speak(std::array<std::unique_ptr<B>, 3>& arr)
{
for (auto& b: arr)
{
b->speak();
}
}
int main()
{
std::array<std::unique_ptr<Derived1>, 3> arr =
{
std::unique_ptr<Derived1>(new Derived1),
std::unique_ptr<Derived1>(new Derived1),
std::unique_ptr<Derived1>(new Derived1)
};
force_speak(arr);
return 0;
}
从编译时已知为派生类的类调用虚方法时是否存在性能损失? 见下面的代码。
这取决于。 大多数编译器会像这样“去虚拟化”代码:
Derived1 d;
d.speak();
对象的动态类型在调用站点是已知的,因此编译器可以避免通过vtable进行调用,并且可以直接调用Derived1::speak()
。
在您的示例中,编译器需要更智能,因为在force_speak
您只有Derived1*
指针(存储在unique_ptr
对象中),并且在该上下文中,不清楚指向对象的动态类型是Derived1
还是更多派生类型。 编译器要么需要force_speak
的调用内联到main
(动态类型已知的位置),要么使用一些关于类型的其他知识来允许虚拟化发生。 (作为附加知识的一个示例,整个程序优化可以确定在程序中的任何位置都没有声明其他派生类型,因此Derived1*
必须指向Derived1
。)
使用C ++ 11 final
关键字可以帮助编译器对某些情况进行虚拟化,例如,如果Derived1
被标记为final
那么编译器就知道Derived1*
只能指向Derived1
而不是指向它的某些其他类型可能会覆盖speak()
它依赖于编译器。 编译器必须静态地知道Derived1:speak()
是唯一的选择。 这包括知道没有一些Derived2::speak()
定义,其中class Derived2: public Derived1
。 但编译器可能根本不会实现这样的优化。
函数模板参数可以由编译器自动推导出来。 这是C ++标准的一部分。 编译器知道呼叫站点的参数类型,因此用户无需提供它。 注意,用户可以提供类型,并且例如可以提供类型兼容但与实际参数的类型不同的类型。
在这种特定情况下,答案可能是 。
如果编译器决定内联force_speak()
,理论上可以推断出数组中的所有指针都是Derived1
实例,因此静态调用该方法。 (标准不需要此优化,因此无论是静态调用还是虚拟调用方法,都取决于您的特定编译器以及编译期间使用的选项。)
如果编译器没有内联调用,那么它必须发出虚拟调用方法的指令,因为你可以进一步派生类Derived1
并再次覆盖该方法,将该类的实例存储在std::unique_ptr<Derived1>
,并传递进入函数的数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.