这似乎是一个基本问题,但我没有看到它问:
假设以下简单案例:
没有虚拟成员.
虚拟继承用于允许多个路径到同一个基础.
根据访问派生类最多的成员所需的时间,虚拟继承的价格是多少?特别是,如果存在非零价格,它是否仅适用于通过多个路径继承的成员或其他成员?
根据访问派生类最多的成员所需的时间,虚拟继承的价格是多少?
一个偏移量查找和一个添加(2个指令和一个内存提取)
特别是,如果存在非零价格,它是否仅适用于通过多个路径继承的成员或其他成员?
是的,即便如此也并非总是如此.如果编译器有足够的信息来证明访问不需要通过间接访问,则可以在编译时自由地使查找短路.
在这种情况下,确切地澄清确切可能是件好事. - Nicol Bolas
先生说得好.
这是一个证明这一点的例子.使用-O2和-S选项进行编译,以查看实施中的优化.
#include#include enum class proof { base, derived }; // volatile forces the compiler to actually perform reads and writes to _proof // Without this, if the compiler can prove that there is no side-effect of not performing the write, // it can eliminate whole chunks of our test program! volatile proof _proof; struct base { virtual void foo() const { _proof = proof::base; } virtual ~base() = default; }; struct derived : base { void foo() const override { _proof = proof::derived; } }; // factory function std::unique_ptr make_base(const std::string&name) { static const std::string _derived = "derived"; // only create a derived if the specified string contains // "derived" - on my compiler this is enough to defeat the // optimiser if (name == _derived) { return std::make_unique (); } else { return {}; } } auto main() -> int { // here the compiler is fully aware that p is pointing at a derived auto p = std::make_unique (); // therefore the call to foo() is made directly (in fact, clang even inlines it) p->foo(); // even here, the compiler 'knows' that b is pointing at a 'derived' // so the call to foo is made directly (and indeed on my compiler, completely // inlined) auto b = std::unique_ptr (new derived); b->foo(); // here we assign a derived to b via indirect construction through a string. // Unless the compiler is going to track this string and follow the logic in make_base // (and on my compiler it does not) this will prevent the virtual call to foo() from // being turned into a direct call. // Therefore, this call will be made via the virtual function table of *b b = make_base("derived"); if (b) { b->foo(); } return 0; }