考虑这个简单的例子:
class Base {
virtual void foo() {};
};
class Derived: public Base {
void foo() {};
};
Base *b = new Derived;
Derived *d = new Derived;
b->foo();
d->foo();
我的问题是:通过派生类指针调用在基类(但不在派生类中)中声明为虚拟的成员函数是否使用vtable机制(并付出代价)?在示例b->foo()
中使用vtable机制来调用Derived::foo()
,但是d->foo()
?
如果是,那么如何规避这种行为:当明确使用Derived
指针时,我想直接调用Derived::foo()
方法而不支付vtable的成本,就好像基类没有存在?
答案 0 :(得分:6)
语法
d->Derived::foo();
将禁止虚拟调度,并保证函数Derived::foo
是被调用的函数,即使存在重写函数也是如此。
这很少是你想要的,但我不能建议其他解决方案,除非你解释为什么要这样做。例如,在给出的代码片段中,没有理由为什么应该动态分配Derived
。你可以写一下:
Derived d;
d.foo();
这里,编译器确定动态类型为Derived
,因此不需要虚拟调度。
答案 1 :(得分:2)
调用在基类中声明为virtual的成员函数(但不在deverived类中)...
我已停止阅读此处,因为如果Base
将foo
声明为虚拟,Derived
只能覆盖foo
,Derived::foo
(据称是签名匹配) )隐含virtual
。
Derived::foo
的以下定义相同:
class Derived: public Base {
void foo() {};
};
class Derived: public Base {
virtual void foo() {};
};
此机制称为隐式虚拟传播,this SO answer tries and explain why id was conceived that way。以下是它的基本原理:
10.3虚拟功能
2如果在类
vf
和类Base
中声明虚拟成员函数Derived
,直接或间接从Base
派生,则成员函数{{ 1}}具有相同的名称,声明参数类型列表(8.3.5),cv-qualification和ref-qualifier(或缺少相同)vf
,然后Base::vf
也是虚拟(是否如此声明)并覆盖Derived::vf
。