在哪里指定内联关键字,base class,derived class 或两者都重要吗?
Does it matter where is the inline keyword is specified, base class, derived class or both?
假设我们不想提示编译器在适用的情况下内联成员函数。
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()
隐式指定的还是我需要再次显式键入它?
Do I need to specify inline
in Derived::f()
or can I omit the keyword and be sure that virtual Derived::f()
is the same thing as inline Derived::f()
?
如果在导出的class中省略inline
关键字,则在导出的class中不是inline
。
I mean is the inline
keyword implicitly specified for Derived::f()
不,不是。
or do I need to explicitly type it once again?
是的,你知道。但是,编译器很可能会为其生成代码,就好像它是一个非 inline
成员函数一样,因为它是一个 virtual
成员函数。
内联关键字有什么作用?
现代编译器试图平衡内联函数的成本与收益。
好处和成本都很清楚:当一个函数被内联时,函数调用没有开销(因为没有函数调用),并且编译器能够对函数体进行优化基于调用它的上下文的函数(因为当它被内联时,它知道该上下文)。
成本可能包括增加可执行文件的大小(如果它是一个大函数),以及在可执行文件周围贴满函数主体的更多程序集实例。
一个经验法则是,如果一个函数很大或很复杂,它可能不会被内联。如果它很小,它可能会被内联。
这很好。它可以防止臃肿的可执行文件,但仍然消除了几乎所有与使用函数相关的开销。执行一个大而复杂的函数所花费的时间通常 相形见绌 函数调用的成本,并且内联它只会带来最小的好处。
那么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 调用它,编译器不会提前知道要调用什么函数:
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();
}
但是,如果您从 class 的具体实例调用它(不是引用,也不是指针,编译器会确切地知道调用的是哪个版本:
int getNumFromDerived() {
Derived d;
// Here, we know that we're calling Derived::getNum()
// so the compiler *can* inline it.
return d.getNum();
}
您应该如何应用内联关键字?
您可以在基础 class 和派生 class 中指定它。只知道 不会 保证它们被内联,正是因为有时内联虚函数调用是不可能的。
有其他选择吗?
因为模板保留了类型信息,所以编译器总是知道要调用哪个函数。内联模板化函数调用很容易,使用它们不会增加程序的开销。
如果可能,首选模板而不是虚拟继承。
假设我们不想提示编译器在适用的情况下内联成员函数。
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()
隐式指定的还是我需要再次显式键入它?
Do I need to specify
inline
inDerived::f()
or can I omit the keyword and be sure thatvirtual Derived::f()
is the same thing asinline Derived::f()
?
如果在导出的class中省略inline
关键字,则在导出的class中不是inline
。
I mean is the
inline
keyword implicitly specified forDerived::f()
不,不是。
or do I need to explicitly type it once again?
是的,你知道。但是,编译器很可能会为其生成代码,就好像它是一个非 inline
成员函数一样,因为它是一个 virtual
成员函数。
内联关键字有什么作用?
现代编译器试图平衡内联函数的成本与收益。
好处和成本都很清楚:当一个函数被内联时,函数调用没有开销(因为没有函数调用),并且编译器能够对函数体进行优化基于调用它的上下文的函数(因为当它被内联时,它知道该上下文)。
成本可能包括增加可执行文件的大小(如果它是一个大函数),以及在可执行文件周围贴满函数主体的更多程序集实例。
一个经验法则是,如果一个函数很大或很复杂,它可能不会被内联。如果它很小,它可能会被内联。
这很好。它可以防止臃肿的可执行文件,但仍然消除了几乎所有与使用函数相关的开销。执行一个大而复杂的函数所花费的时间通常 相形见绌 函数调用的成本,并且内联它只会带来最小的好处。
那么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 调用它,编译器不会提前知道要调用什么函数:
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();
}
但是,如果您从 class 的具体实例调用它(不是引用,也不是指针,编译器会确切地知道调用的是哪个版本:
int getNumFromDerived() {
Derived d;
// Here, we know that we're calling Derived::getNum()
// so the compiler *can* inline it.
return d.getNum();
}
您应该如何应用内联关键字?
您可以在基础 class 和派生 class 中指定它。只知道 不会 保证它们被内联,正是因为有时内联虚函数调用是不可能的。
有其他选择吗?
因为模板保留了类型信息,所以编译器总是知道要调用哪个函数。内联模板化函数调用很容易,使用它们不会增加程序的开销。
如果可能,首选模板而不是虚拟继承。