我最近决定使用非虚拟接口惯用法(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()
会被标记为内联的候选者吗? 不是虚拟函数,但仍然调用< / em>一个虚函数。它是否可以内联?
额外的问题:它值得吗?正文只包含一个陈述。
请注意,这个问题非常适合学习它,而不是在任何地方搜索优化。我知道这个函数只会被调用几次(好吧,现在,所以对于程序如何演变也可能是谨慎的),并且内联将是相当多余的,而不是关于我的程序性能的主要关注点。 / p>
谢谢!
答案 0 :(得分:2)
我知道在标题中提供函数体会自动将函数标记为内联的候选函数
或多或少;但是你可以通过在类定义中提供函数体来实现,或者通过在标题中明确声明它inline
来实现。否则,该函数受一个定义规则的约束,如果您将标题包含在多个翻译单元中,则会出现错误。
请注意,这不会强制编译器内联对函数的所有调用;在标题中提供定义只允许它在包含标题的任何翻译单元中内联它,如果它认为它是值得的。此外,即使呼叫站点没有定义,一些编译器也可以执行“整个程序优化”和内联函数。
然后,在这种情况下,func()会被标记为内联的候选者吗?它不是虚函数,但仍然调用虚函数。它是否可以内联?
是的,所有功能都是内联的候选者。如果他们自称,那么显然你无法内联所有的电话;也不是在编译时不知道该函数(例如,因为它必须虚拟调用,或通过函数指针)。在这种情况下,通过虚拟调用func()
,内联函数将取代对doFunc()
的直接调用。
请注意,如果在编译时已知动态类型,则有时可以内联虚拟调用。例如:
struct MyImplementation : Interface {/*whatever*/};
MyImplementation thing;
thing.func(); // Known to be MyImplementation, func and doFunc can be inlined
额外的问题:它值得吗?
这取决于“它”是什么。如果你的意思是编译时间,那么只要函数保持简短,你就可以获得一些好处(如果函数被多次调用,可能很有用),但成本可以忽略不计。如果你的意思是花时间选择把它放在哪里的成本,那么可能不是;把它放在最方便的地方。