使用非虚拟接口习语,可以/将我的非虚拟函数内联
Using the non-virtual-interface idiom, can/will my non-virtual function be inlined ?
我最近决定使用非虚拟接口习惯用法(NVI)在c++中设计一个接口,主要是为了使用具有默认值的参数(从而避免由默认参数静态绑定引起的问题)。
我为我的类准备了一个相当简单的声明,看起来像这样:
class Interface{
public:
void func(Parameter p = 0);
virtual ~Interface();
private:
virtual void doFunc(Parameter p)=0;
};
void Interface::func(Parameter p){ doFunc(p); }
Interface::~Interface() {}
我知道在头文件中提供函数体会自动将函数标记为内联候选函数(尽管我不知道将定义放在类之外是否会阻止这种情况)。我也知道虚函数没有内联的原因很明显(我们不知道哪个函数会在运行时被调用,所以我们不能明显地用函数体代替调用)。
那么,在这种情况下,func()
是否被标记为内联候选?不是虚函数,但仍然调用虚函数。它使它可以内联吗?
附加问题:值得吗主体只包含一条语句。
请注意,这个问题是为了学习它,而不是到处搜索优化。我知道这个函数只会被调用几次(好吧,就目前而言,因此最好谨慎地考虑程序的演变),并且内联将是相当多余的,并且不是我的程序性能的主要关注点。
谢谢!
我知道在头文件中提供函数体会自动将函数标记为内联的候选函数
More or less;但是你可以通过在类定义中提供函数体来做到这一点,或者通过显式地声明它inline
,如果它在头文件中。否则,该函数将受到"一个定义规则"的约束,如果在多个翻译单元中包含标头,则会出现错误。
注意,这并不强制编译器内联所有对函数的调用;在头文件中提供定义只是允许它将其内联到任何包含头文件的翻译单元中,如果它认为值得这样做的话。此外,一些编译器可以执行"整个程序优化",甚至在调用处没有定义时也可以执行内联函数。
那么,在这种情况下,func()会被标记为内联候选吗?它不是虚函数,但仍然调用虚函数。
是的,所有函数都可以内联。如果它们调用自己,显然你不能内联所有的调用;如果函数在编译时不知道(例如,因为它必须虚拟调用,或通过函数指针)。在这种情况下,内联函数将用对doFunc()
的虚拟调用取代对func()
的直接调用。
请注意,如果动态类型在编译时已知,有时可以内联虚拟调用。例如:
struct MyImplementation : Interface {/*whatever*/};
MyImplementation thing;
thing.func(); // Known to be MyImplementation, func and doFunc can be inlined
附加问题:值得吗?
这取决于"它"是什么。如果您指的是编译时间,那么只要函数保持较短,您可能会获得一些好处(如果函数被多次调用,则可能是显著的),而成本可以忽略不计。如果你指的是花时间选择放置地点的成本,那么可能不是;把它放在最方便的地方。
- 为什么在这种情况下不调用我的虚拟函数实现?
- 我是否应该在包含虚拟方法的类上使用'memcpy'?如果没有,如何替换它?
- 如果我有指向基类对象的指针,如何获取虚拟方法的地址?
- 为什么我的虚拟破坏者多次执行这些执行
- 我是否错过了什么,或者虚拟呼叫的性能并不像人们所说的那样糟糕
- 我如何确保从我的派生类中调用纯虚拟方法
- 为什么虚拟功能打破了我的铸造
- getPeername()在客户端在虚拟机上运行时返回我的本地主机地址
- 在这种情况下,我的派生类是否还需要一个虚拟析构函数
- 我可以使用覆盖非虚拟方法的方法吗?
- 当我的基类和派生类具有相同的函数时,它必须是虚拟的吗?
- 我在哪里可以找到C++有状态虚拟基础的良好解释
- 如何确定为我的程序保留了多少虚拟内存
- 为什么我的输出流seg出错,而我的虚拟析构函数不起作用,但当我杀死虚拟的时候,它起作用了
- 为什么我没有得到虚拟打印机的上下文?
- 我正在使用放置新功能和虚拟功能;为什么我的虚拟功能表有误?
- 我的基类中有一个虚拟析构函数和一个数组.我怎样才能让它发挥作用
- 为什么我不能继承虚拟基的构造函数?
- 使用非虚拟接口习语,可以/将我的非虚拟函数内联
- 子类QCompleter,虚拟槽在我的子类没有被调用