我必须展示无法在 C++ 中内联的函数。
为了检查这一点,我设置了标志 -Winline
。
使用递归函数,我可以生成一个不能内联的函数。
但我对继承和“virtual”关键字进行了同样的尝试。但是我无法让编译器提示无法内联某些内容。
我知道这个话题已经涉及了很多。但我只是没有找到一个有效的例子。我的编译器“聪明”吗:-)
我试过这个:
class virt1
{
public:
virt1(){};
inline virtual int virtFunc(int a){ return a*a; };
virtual ~virt1(){};
};
class virt2 : public virt1
{
public:
virt2(){};
inline virtual int virtFunc(int a){ return a+a;};
virtual ~virt2(){};
};
void testVirtFunc(virt2 &obj)
{
std::cout << obj.virtFunc(2);
}
最佳答案
没有“可内联”或“不可内联”函数这样的概念。函数只有可内联或不可内联的调用。被声明为inline
的属性是函数本身的属性。可内联(或不可内联)的属性是特定调用的属性。这是两个不同的概念。
您似乎在混合这两个完全不相关的概念。
每个函数都可以声明为内联
。虚函数可以声明为内联
。递归函数也可以声明为 inline
。这没什么奇怪的。您认为这是某种非法行为的期望是完全没有根据的。声明一个函数 inline
总是合法的。
同时,对这些函数的实际调用是否会被内联是一个完全不同的、独立的问题。对某个函数的一个调用可以是可内联的,而对同一函数的另一个调用可以是不可内联的。 “可内联”再次成为每次调用的属性。
确实不能内联动态调度的虚拟调用。同时,在智能编译器可以在编译时正确预测虚拟调用中使用的对象的动态类型的情况下,编译器可能会生成对虚拟函数的直接调用(不使用动态调度的调用)。此调用可以轻松内联。
例如,给定你的声明,这个调用
virt1 *v = rand() % 2 ? new virt1() : new virt2();
v->virtFunc(5);
不能内联。但是这些电话
virt2 v2;
v2.virtFunc(6);
virt1* v1 = &v2;
v1->virtFunc(7);
可以毫无问题地内联。
通过指向函数的指针进行的间接调用通常不能内联。但是,如果编译器在编译时以某种方式知道指针的确切值,则可以将调用替换为直接调用和内联。
递归函数调用也可以内联(尽管你不这么认为)。它们可以内联到某个固定的递归深度。这就是大多数编译器内联递归函数的方式:它们使用深度限制内联来“展开”递归,就像展开循环一样。
关于c++ - 不可内联的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19942034/