关于C++模板分离式编译

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wk_bjut_edu_cn/article/details/85038035

以前一直没注意这个问题,下面进行总结

分离编译模式

一个项目如果有多个源文件组成,每个源文件单独编译,形成目标文件。最后通过链接器将所有的目标文件链接起来,形成一个可执行的文件。这个过程就叫做分离编译。

模板不能分离编译

有一个项目,其中函数声明放在”test.h”中,函数实现放在”test.cpp”中,函数调用放在”main.cpp”中。如果没用使用模板,将不会有任何问题。而且这样是被推荐使用的。但是如果有函数的实现是模板函数或有模板类,将会出现链接错误。代码如下:

//在头文件fun.h中
#include<iostream>
template<class T>
class A {
public:
	void func(T t);
};

//在源文件fun.cpp中
#include<iostream>
#include"fun.h"
template<class T>
void A<T>::func(T t)
{
	std::cout << t << std::endl;
}

//在main.cpp中
#include<iostream>
#include"fun.h"
int main(void)
{
	A<int> k;
	k.func(2);
	system("pause");
	return 0;
}

方法一

现在我才想起来以前写stl的时候,出现这个错误,死活想不到是什么原因。

来看一下我在前段时间写stl时的一种正确的处理方法

//在头文件fun.h中
#include<iostream>
template<class T>
class A {
public:
	void func(T t);
};

//在头文件fun.impl.h中
#include<iostream>
template<class T>
void A<T>::func(T t)
{
	std::cout << t << std::endl;
}

//在main.cpp中
#include<iostream>
#include"fun.h"  //1
#include"fun.impl.h"//2
//1和2都必须包含,否则会报错
int main(void)
{
	A<int> k;
	k.func(2);
	system("pause");
	return 0;
}

这种方法可以通过编译,其实原理很简单,在C++中类模板不支持分离式编译,即我们必须把类模板的声明和定义写在.h文件中,因为头文件的数据相当于全局变量,所以其实就是相当于在一个头文件中既声明又定义,如果写在两个头文件中,方便我们编写,但实质还是在头文件中同时声明和定义。

方法二

//在头文件fun.h中
#include<iostream>
template<class T>
class A {
public:
	void func(T t);
};

//在源文件fun.cpp中
#include<iostream>
#include"fun.h"
template<class T>
void A<T>::func(T t)
{
	std::cout << t << std::endl;
}

//在main.cpp中
#include<iostream>
#include"fun.cpp"
int main(void)
{
	A<int> k;
	k.func(2);
	system("pause");
	return 0;
}

这种解决方法直接包含了实现文件,让编译器直接找到定义和实现,这样的效果跟把定义和实现都放在fun.h里是一样的。所以原理还是和方法一一样。

为什么C++C++编译器不能支持对模板的分离式编译

C++是分别单独编译,对于每个cpp文件,预编译为编译单元,编译的时候不需要其他文件,可生成obj文件,然后链接成exe文件。当.h中声明了一个方法模板,.cpp中顶一个方法模板,在main函数中包含.h文件,然后使用模板方法。单独编译.cpp,并不会生成特定版本的方法,因为C++规定,模版只有在使用的时候,才实例化一个方法。在main.cpp中,相当于声明了模版方法,但是不知道模版方法的定义,因此也没法实例化模版方法,只能希望连接器在其他的obj文件中,找到对应的实例化方法。但是在连接的时候,找不到对应的方法,连接错误。

上面问题的关键是:C++单独,分别编译。Fun.cpp定义了模版方法,但是没有使用,因此不会实例化模版方法。而在main.cpp中,使用了模版方法,但是不知道模版方法的定义,也没办法实例化方法,只能寄希望于连接的时候,从其他obj中找到,当然找不到,就出错了。

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/85038035