在哪里指定内联关键字、基类、派生类或两者是否重要?
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()
隐式指定的,还是我需要再次显式键入它?
我是否需要在
Derived::f()
中指定inline
,或者我可以省略关键字并确保virtual Derived::f()
与inline Derived::f()
相同?
如果在派生类中省略inline
关键字,则不会inline
派生类中
我的意思是为
Derived::f()
隐式指定的inline
关键字
不,不是。
还是我需要再次显式键入它?
是的,你愿意。但是,编译器很可能会为其生成代码,就好像它是非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 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();
}
您应该如何应用内联关键字?
可以在基类和派生类中指定它。只要知道它不能保证它们被内联,正是因为有时不可能内联虚拟函数调用。
有其他选择吗?
由于模板保留类型信息,因此编译器始终知道要调用哪个函数。内联模板化函数调用很容易,使用它们不会增加程序的开销。
如果可能,首选模板而不是虚拟继承。
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 是否可以为 QPixmap 派生类嵌入缩放方法?
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- 是否可以使用 using 将基类中的公共成员重新声明为派生类中的私有成员?
- 将基本实例指针强制转换为派生实例指针是否合法?(实例不是派生实例)
- 从模板基类派生是否在派生类声明的点实例化模板
- 是否可以将CRTP与本身已模板化的派生类一起使用
- C++多态性:如何测试一个类是否派生自另一个基类
- 如果所有派生类在编译时都是已知的,那么final关键字是否提供了优化
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- 派生类是单例是否是一种好的做法
- C++ 多态性:如果派生类中的虚函数在基类中声明了常量,是否需要将其声明为常量
- 是否可以从派生类返回基类的实例?
- 如何检查变量是否派生自类?
- 用于确定一个类是否派生自另一个类的代码说明
- 如何测试类B是否派生自类的模板族
- 是否可以在编译时检查类型是否派生自模板的某个实例化
- 如何知道两个对象是否派生自同一基类
- 检查类是否派生自特定类(编译,运行时两个答案都可用)