在哪里指定inline关键字,基类,派生类或两者都重要?

时间:2019-03-27 03:53:20

标签: c++ inheritance inline virtual

假设我们不会在适当的情况下提示编译器使用内联成员函数。

class Base
{
 public:
      inline virtual f() = 0;
};

class Derived : public Base
{
 public:
      virtual f() override; // no inline specifier here
};

我需要在inline中指定Derived::f()还是可以省略关键字,并确保virtual Derived::f()inline Derived::f()是同一个人?

我的意思是为inline隐式指定了Derived::f()关键字,还是我需要再次明确地键入它?

2 个答案:

答案 0 :(得分:4)

  

我需要在inline中指定Derived::f()还是可以省略关键字,并确保virtual Derived::f()inline Derived::f()是同一个人?

如果在派生类中省略了inline关键字,则在派生类中不是inline

  

我的意思是为inline隐式指定的Derived::f()关键字

不,不是。

  

还是我需要再次明确输入?

是的,你知道。但是,编译器很可能会为它生成代码,就好像它是非inline成员函数一样,因为它是virtual成员函数。

答案 1 :(得分:1)

内联关键字有什么作用?

现代的编译器试图平衡内联函数的成本和好处。

好处和代价都非常清楚:当内联函数时,函数调用没有开销(因为没有函数调用),并且编译器能够基于函数对函数体进行优化(在被内联时,它知道该上下文)。

成本可能包括增加的可执行文件大小(如果它是一个大功能),并且将函数主体的程序集的更多实例粘贴在可执行文件周围。

经验法则是,如果一个函数很大或很复杂,则可能不会内联。如果很小,则可能会内联。

这很好。它可以防止可执行文件膨胀,但是仍然消除了几乎所有与使用函数相关的开销。执行大型复杂函数的时间通常会使函数调用的成本矮小,并且内联它只会带来最小的收益。

inline的作用是什么?编译器在决定内联函数时会计算其复杂程度。然后将计算结果与某个阈值进行比较。如果函数的复杂度小于阈值,则将函数内联。

inline关键字基本上会提高该特定功能的阈值,但实际上它的作用因编译器而异。

是否可以内联所有函数调用?

如果编译器不知道调用了哪个函数,则无法内联它。

让我们看一个例子:

// func_t is a pointer to a function that returns an integer
using func_t = int(*)(); 
int getNumber(func_t func) {
    // The compiler can't inline func(), because it doesn't know
    // what func *is*
    return func(); 
}

这如何适用于虚函数?

虚拟函数调用与调用函数指针非常相似,但有一些关键区别。如果要从基类中调用它,则编译器不会提前知道要调用什么函数:

class Base {
    virtual int getNum() { return 0; }
};

class Derived {
    int value; 
    void setValue(int v) { value = v; }
    int getNum() override { return value; }
}; 

int getNumFrom(Base& base) {
    // The compiler doesn't know whether to call
    // Base::getNum() or Derived::getNum(), so it can't inline it
    return base.getNum();
}

但是,如果要从类的具体实例(不是引用,而不是指针)中调用它,则编译器会确切知道要调用哪个版本:

int getNumFromDerived() {
    Derived d; 
    // Here, we know that we're calling Derived::getNum()
    // so the compiler *can* inline it. 
    return d.getNum(); 
}

您应该如何应用内联关键字?

您可以在基类和派生类中都指定它。只是知道不会保证它们被内联,正是因为有时无法内联虚拟函数调用。

有其他选择吗?

由于模板保留类型信息,因此编译器始终知道要调用哪个函数。内联模板函数调用很容易,并且使用它们不会增加程序的开销。

如果可能,请选择模板而不是虚拟继承。