C++ 指定内联关键字的位置、基类、派生类或两者都有关系吗?

C++ 指定内联关键字的位置、基类、派生类或两者都有关系吗?,c++,inheritance,inline,virtual,C++,Inheritance,Inline,Virtual,假设我们不想在适用的情况下提示编译器使用内联成员函数 class Base { public: inline virtual f() = 0; }; class Derived : public Base { public: virtual f() override; // no inline specifier here }; 我是否需要在Derived::f()中指定inline,或者我是否可以省略关键字并确保virtual-Derived::f()与inli

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

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

class Derived : public Base
{
 public:
      virtual f() override; // no inline specifier here
};
我是否需要在
Derived::f()
中指定
inline
,或者我是否可以省略关键字并确保
virtual-Derived::f()
inline-Derived::f()相同

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

我是否需要在
Derived::f()
中指定
inline
,或者我是否可以省略关键字并确保
virtual-Derived::f()
inline-Derived::f()相同

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

我的意思是为
派生::f()

不,不是

或者我需要再次显式地键入它吗

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

内联关键字做什么? 现代编译器试图平衡函数内联的成本和好处

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

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

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

这很好。它防止了膨胀的可执行文件,但仍然消除了几乎所有与使用函数相关的开销。执行大型复杂函数的时间通常会使函数调用的成本相形见绌,而将其内联的好处也微乎其微

那么
内联
做什么呢?
编译器在决定内联函数时会计算函数的复杂程度。然后将该计算与某个阈值进行比较。如果函数没有阈值复杂,则将函数内联

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(); 
}
如何应用内联关键字? 您可以在基类和派生类中都指定它,只需知道它不能保证它们是内联的,正是因为有时无法内联虚拟函数调用

还有其他选择吗? 由于模板保留类型信息,编译器总是知道调用哪个函数。内联模板函数调用很容易,使用它们不会增加程序开销


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

编译器极不可能注意虚拟方法的
内联
关键字。只有在编译器能够证明类的最派生实例是什么的情况下,才可能在这一领域进行任何优化。只有现实地适用于在静态或自动作用域中创建的对象实例。通过指针或引用引用时不太可能。如果您不打算在标头中提供函数的实际实现,则任何数量的
inline
关键字都不会有帮助。如果在调用站点上看不到实现,则没有任何内容可内联。此外,虚拟函数调用通常不能内联-编译器无法确定在编译时需要调用哪个重写。因此,如果函数是在头中定义的,而对象不是由指针或引用引用的,那么内联是最有可能的,但在这种情况下,内联是在基或派生中指定的又有什么关系呢d类还是两者都有?这正是困扰我的地方。很抱歉,我发现你的anwser有些含糊不清,首先你说我不需要在派生类中指定内联,然后你说我需要显式指定关键字。你能重写你的第一个anwser吗。(三分之一)