假设我想使用两个方法创建一个类Base
:foo(int)
和bar(int)
。我希望以以下方式定义它们:
Base::foo
必须在派生的非抽象类中重写Base::bar
不能在派生类中重写第一个目标可以通过将foo
标记为virtual int foo(int) = 0
使其抽象来实现。通过将bar
标记为virtual int bar(int) final
以使其最终化,可以满足第二个要求。这是结果代码:
class Base
{
public:
virtual int foo(int n) = 0;
virtual int bar(int n) final
{
return n + 42;
}
};
以及从Base
派生的示例类:
class Derived : Base
{
public:
virtual int foo(int n) override
{
return n * n;
}
int bar(int n) // compilation error here
{
return n + 43;
}
};
正如我们想要的那样,尝试覆盖Base::bar
已触发编译错误。
现在,我的问题是:将函数标记为virtual final
是否会引起开销,因为即使函数不能被重写,但函数仍为virtual
(动态分配)?
不要介意缺少虚拟析构函数~Base()
,此处不是要缩短代码的地方。
编译器可能会取消虚拟化此调用:
struct Base {
virtual int bar(int n) final {
return n + 42;
}
};
struct Derived : Base { };
int foo(Derived& d, int n) {
return d.bar(n);
}
[becomes与-O1
:
foo(Derived&, int):
lea eax, [rsi+42]
ret
如果没有final
,我们将得到一个间接调用:
foo(Derived&, int):
sub rsp, 8
mov rax, QWORD PTR [rdi]
call [QWORD PTR [rax]]
add rsp, 8
ret
在您的情况下,没有开销,因为您的类不会从任何类继承来定义您的最终函数,因此,无论虚拟声明如何,编译器都会生成对其地址的直接调用。