3

我最近决定使用非虚拟接口习惯用法 (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()被标记为内联候选?不是虚函数,但仍然调用虚函数。它是否可以内联?

额外的问题:值得吗?正文只包含一个语句。

请注意,这个问题非常适合学习它,而不是到处搜索优化。我知道这个函数只会被调用几次(好吧,就目前而言,最好谨慎对待程序的发展方式),并且内联将是相当多余的,而不是我程序性能的主要关注点。

谢谢 !

4

1 回答 1

2

我知道在标头中提供函数体会自动将函数标记为内联候选

或多或少; 但是您可以通过在类定义中提供函数体来实现,或者inline如果它在标头中则显式声明它。否则,该函数受单一定义规则的约束,如果您将标题包含在多个翻译单元中,则会出现错误。

请注意,这并不强制编译器内联对函数的所有调用;在标题中提供定义只允许它在包含标题的任何翻译单元中内联它,如果它认为这是值得的。此外,一些编译器可以执行“整个程序优化”和内联函数,即使在调用站点没有定义时也是如此。

那么,在这种情况下, func() 会被标记为内联候选吗?它不是虚函数,但仍然调用虚函数。它是否可以内联?

是的,所有函数都是内联的候选函数。如果他们调用自己,那么显然你不能内联所有的调用;如果函数在编译时是未知的(例如,因为它必须被虚拟调用,或者通过函数指针)。在这种情况下,内联函数会将直接调用替换为对func()的虚拟调用doFunc()

请注意,如果动态类型在编译时已知,则有时可以内联虚拟调用。例如:

struct MyImplementation : Interface {/*whatever*/};
MyImplementation thing;
thing.func(); // Known to be MyImplementation, func and doFunc can be inlined

额外的问题:值得吗?

这取决于“它”是什么。如果您的意思是编译时间,那么只要函数仍然很短,您可能会以微不足道的成本获得一些好处(如果函数被多次调用,可能会很重要)。如果您的意思是花时间选择放置它的成本,那么可能不是;把它放在最方便的地方。

于 2013-05-15T09:18:28.300 回答