为什么在 C++ 中 inline 函数要在头文件中定义

先说结论:

  • inline 函数并不是必须定义在头文件中,但是一个好的工程习惯是将其定义在头文件中。
  • (核心)inline 函数在链接的时候仅仅在单个 cpp 文件中“可见”,并不是全局“可见”,其实是因为 inline 函数没有被编译成汇编码,无法用于链接。
  • inline函数仅仅是一个建议,对编译器的建议,最后能否真正内联,还要看编译器,并不是说声明了内联就会内联,声明内联只是一个建议而已。
  • C++ 中在类中实现的成员函数会被编译器自动默认判定为 inline 函数。

对于以下三个文件做测试:
test.h

// test.h
#include <iostream>
class Test{
    
    
public:
	void func();
};

test.cpp

//test.cpp
#include "test.h"
inline void Test::func()
{
    
    
	std::cout<<"Hello, inline!"<<std::endl;
}

client1.cpp

#include "test.h"
int main()
{
    
    
	Test a;
	a.func();
	return 0;
}

我们将 Test 类中的 func 成员函数作为内联函数实现在 test.h 头文件所对应的 test.cpp 文件中,然后在 client1.cpp 中调用,用GCC编译的时候报链接错误如下:
在这里插入图片描述
链接器报错表示在 main 函数中调用的 func 函数是未定义的,由此可知内联函数与普通函数不同,其仅仅在本文件内可见,而不是全局可见的。如果将上述代码中 func 内联函数的定义写入到 test.h 头文件中,则可以正确的编译运行。

同时我们也可以得出结论,内联函数可以不在头文件中定义,但是在每个需要用到他的文件里面都需要对其定义,甚至可以有不同的定义,虽然这是行得通的,但是这好像违背了初衷,所以一般将内联函数的定义实现在头文件中

由此我们可以回答以下问题:

1、inline 函数和普通函数链接的区别?
普通函数是整个工程可见的,可以跨文件链接,而 inline 函数仅仅当前文件可见,不可以跨文件链接。

2、inline 函数的定义必须写在头文件中吗?
不必须。但是如果不写在头文件中,那么在每一个调用了 inline 函数的文件中都必须有该 inline 函数的定义,且每个文件中定义可以不同,相当于不同文件中的同名 inline 函数实际上不是同一个函数。

3、为什么类中定义的函数会被编译器自动判定为 inline 函数?
因为在工程中,类的定义通常写在某个头文件中,任何想要使用该类的源文件都需要先包括该头文件,如果在类中定义的函数不是 inline 函数,则有可能出现多重定义的问题。比如说有一个头文件定义了一个类,且该类中有一个实现在类里面的成员函数,工程中有两个源文件都包含了该头文件,那么经过预处理后,相当于在两个源文件中都有对该成员函数的定义,如果该成员函数没有被编译器判定为 inline 函数,则在链接的时候会出现多重定义的错误。

4、原理是什么?
因为 inline 函数在编译的时候就被插入到调用处,编译器不会单独为一个 inline 函数生成汇编代码,而是在调用的地方直接生成汇编代码插入到调用处,这个是属于编译阶段的事情而不是链接阶段的事情,所以在编译的代码生成阶段就需要拿到 inline 函数的定义。如果编译器在编译的代码生成阶段没有拿到 inline 函数的定义,则将对其的调用推迟到链接时,但是由于对于 inline 函数的定义处,编译器并未生成汇编代码,所以会链接失败。

猜你喜欢

转载自blog.csdn.net/qq_21746331/article/details/114321379
今日推荐