我认为我之前已经问过我的问题,我确实已经阅读了它们,但仍然有点困惑,因此要求说清楚。
The C++ standard says all member functions defined inside class definition are inline
我也听说编译器可以忽略函数的内联。在上述情况下是否会成立,或者如果在类定义中定义它将始终内联?
此外,这个设计背后的原因是什么,使所有函数在类定义中内联定义?内联与源文件和头文件有什么关系?
更新:所以如果不要内联,那么应该总是在课外定义他们的函数,对吗?
JohnB更新2:在类定义中声明的两个函数永远不能互相调用,因为它们必须包含另一个函数的整个主体。在这种情况下会发生什么?(已由Emilio Garavaglia回答)
答案 0 :(得分:37)
出现混乱,因为内联有两个影响:
第1点是“过时的”,因为编译器实际上可以按照自己喜欢的方式来优化代码。它总是“内联”机器代码,如果它可以并且发现方便,如果它不能,它将永远不会那样做。
第2点是该术语的实际含义:如果你在标题中define
(指定正文)一个函数,由于标题可以包含在更多的源中,你必须告诉编译器通知关于定义重复的链接器,以便它们可以合并。
现在,根据语言规范,自由函数(未在类体中定义)默认情况下未定义为内联,因此在标题中定义类似
的内容void myfunc()
{}
如果标头包含在更多源中,然后在同一输出中链接,则链接器将报告多重定义错误,因此需要将其定义为
inline void fn()
{}
对于类成员,默认情况相反:如果您只声明它们,则不会内联它们。如果您定义它们,它们将是内联的。
所以标题看起来应该是
//header file
class myclass
{
public:
void fn1()
{} //defined into the class, so inlined by default
void fn2();
};
inline void myclass::fn2()
{} //defined outside the class, so explicit inline is needed
如果myclass::fn2()
定义属于正确的来源,则必须丢失inline
关键字。
答案 1 :(得分:10)
inline
关键字具有函数2含义:
inline
函数的地方,不要为它生成函数调用,只需放置函数的内容即可
在它的调用地方(这类似于宏
更换,但输入安全)inline
函数生成多个定义,只生成所有共同的单个定义(例外:static
函数)第1个术语(“代码替换”)只是编译器的请求。这可以忽略,因为编译器最好判断是放文本还是函数调用。 (例如,virtual
函数或递归函数不能内联。)
第二个术语(“一个定义规则”)保证由任何符合标准的编译器发生。这将为所有翻译单元仅生成1个定义。这种设施有时可以简化编码器的工作,因为较小的功能可能不希望将其定义放在.cpp
文件中(例如,吸气剂,设定者)。
此外,对于仅{header}构造的template
函数,此效果是必需的。因此,template
函数默认为inline
。
class A {
public:
void setMember (int i) { m_i = i; }
};
在这个例子中,大多数编译器都可以满足这两个术语
class A {
inline virtual ~A () = 0;
};
A::~A() {}
这里编译器只能满足第二个要求。
答案 2 :(得分:8)
使方法函数内联的唯一原因是如果在标题中定义它。
如果在标题中定义方法函数,并且未放入内联关键字,并且在多个标题或源文件中包含标题,则可以获得该方法的多个定义。
9.3 / 2成员函数[class.mfct]中的c ++ 11标准告诉:成员函数可以在其类定义中定义(8.4),在这种情况下,它是内联成员函数(7.1.2)......
答案 3 :(得分:2)
如果inline
关键字指定,编译器可以忽略内联。如果方法实现存在于类定义中,那就是一个不同的东西,并且不能被忽略。 (它可以,但这会使编译器不符合)
设计背后的原因 - 我需要一种机制,你可以实际强制编译器实际内联你的函数,因为inline
关键字并没有强制要求它。但一般来说,内联方法定义仅在getter和setter方法或一些简单的2-liners的情况下完成。和模板,但这是一个不同的问题。
内联与头文件和源文件有关,因为函数的定义必须对编译器可见,因此它知道如何实际内联调用。内联在实现文件中定义的函数比在头文件中定义的函数更难。
编辑:在旁注中,op正在审视的段落为7.1.2.3
:
在类定义中定义的函数是内联函数[...]。
EDIT2:
显然,内联函数和内联替换之间存在一些差异。第一个是函数的属性,它不仅包括内联替换,第二个意味着函数体实际粘贴在调用它的位置。
因此,该函数可以内联,但不能粘贴其体,而不是被调用。
答案 4 :(得分:2)
当定义在类中时,它被视为声明为inline
,因为假定类定义存在于从多个翻译单元使用的头文件中,所以任何非这里的内联定义将违反一个定义规则。
编译器一如既往地可以自由地内联它所想的内容,只要注意显式或隐式内联的函数不会导致链接器错误。如何通过语言规范保持开放 - 内联函数的功能,但也可以降低符号可见性或将符号重命名为特定于翻译单元的名称(就好像该函数位于匿名名称空间中一样) ),或(如他们大多数人所做的那样)与链接器通信可能存在该函数的多个副本,并且它应该丢弃除了其中一个之外的所有副本。
因此,简而言之,它与明确声明为inline
的函数没有任何不同。
答案 5 :(得分:0)
1)C ++标准说在类定义中定义的所有成员函数都是内联的
2)我也听说编译器可以忽略函数的内联
1)是在类声明本身内定义成员函数的时候。即:在头文件中。为此,您不必提供任何关键字(即:inline
)
2)您可以通过明确使用inline
关键字将函数指定为内联。这实际上是对编译器的请求。根据一些优化规则,编译器可能会也可能不会使函数内联。