实现C++模板类头文件和实现文件分离的方法

如何实现C++模板类头文件和实现文件分离,这个问题和编译器有关。

引用<>里的观点:1)标准C++为编译模板代码定义了两种模型:“包含”模型和“分别编译”模型。2)所有编译器都支持“包含”模型,某些编译器支持“分别编译”模型。

问题的提出:(帖子在:http://topic.csdn.net/u/20101215/15/f4f270f2-f0f9-4c5f-8765-1bfde2aeebbf.html)

第一种方法:按C++primer中的“包含”模型,在定义模板类的头文件中的末行用语句:#include "template_compile.cpp"

在类模板头文件template_compile.h中:

 

[cpp]  view plain copy print ?
 
  1. template<class T>  
  2. class base  
  3. {  
  4. public:  
  5.     base() {};  
  6.     ~base() {};  
  7.     T add_base(T x,T y);  
  8. };  
  9. #include "template_compile.cpp"  
 

 

在类模板的实现文件template_compile.cpp中:

 

[cpp]  view plain copy print ?
 
  1. template<class T>  
  2. T base::add_base(T x,T y)  
  3. {  
  4.     return x+y;  
  5. }  
 

 

在使用模板的测试文件use_template.cpp中:

 

[cpp]  view plain copy print ?
 
  1. #include  
  2. #include "template_compile.h"  
  3. using namespace std;  
  4. void main()  
  5. {  
  6.     base<int> bobj;  
  7.     cout<
  8. }  
 

 

这种方法不能通过编译,"template_compile.cpp"文件不能"看见"“template_compile.h"文件。

然而:如果我把类模板的实现文件里代码放在类模板的头文件中,注释掉:#include "template_compile.cpp",编译和运行不会有任何错误。理论上”把类模板的实现文件里代码放在类模板的头文件中“和”在定义模板类的头文件中的末行用语句:#include "template_compile.cpp" “是一致的,但编译器就是通不过。

实验证明:VC9.0不支持C++primer中所说的“包含”模型。

第二种方法:bruceteen提出的:使用define

在类模板头文件template_compile.h中:

 

[cpp]  view plain copy print ?
 
  1. template<class T>  
  2. class base  
  3. {  
  4. public:  
  5.   base() {};  
  6.   ~base() {};  
  7.   T add_base(T x,T y);  
  8. };  
  9. #define FUCK  
  10. #include "template_compile.cpp"  
 

 

在类模板的实现文件template_compile.cpp中:

 

[c-sharp]  view plain copy print ?
 
  1. #ifdef FUCK  
  2. template<class T>  
  3. base::add_base(T x,T y)  
  4. {  
  5.   return x+y;  
  6. }  
  7. #endif  
 

 

测试文件不变。

实验证明:在VC9.0中,这种方法可以实现类模板头文件和实现文件的分离

方法三:

在类模板头文件template_compile.h中:

 

[cpp]  view plain copy print ?
 
  1. template<class T>  
  2. class base  
  3. {  
  4. public:  
  5.     base() {};  
  6.     ~base() {};  
  7.     T add_base(T x,T y);  
  8. };  
 

 

在类模板的实现文件template_compile.cpp中:

 

[c-sharp]  view plain copy print ?
 
  1. #include "template_compile.h"  
  2. template<class T>  
  3. base::add_base(T x,T y)  
  4. {  
  5.     return x+y;  
  6. }  
 

 

在使用模板的测试文件use_template.cpp中:使用#include "template_compile.cpp"

 

[c-sharp]  view plain copy print ?
 
  1. #include  
  2. #include "template_compile.cpp"  
  3. using namespace std;  
  4. void main()  
  5. {  
  6.     base<int> bobj;  
  7.     cout<
  8. }  
 

 

实验证明:在VC9.0中,这种方法可以实现类模板头文件和实现文件的分离。

 

另外实验证明:VC9.0不支持“分别编译”模型。



C++中每一个对象所占用的空间大小,是在编译的时候就确定的,在模板类没有真正的被使用之前,编译器是无法知道,模板类中使用模板类型的对象的所占用的空间的大小的。只有模板被真正使用的时候,编译器才知道,模板套用的是什么类型,应该分配多少空间。这也就是模板类为什么只是称之为模板,而不是泛型的缘故。

既然是在编译的时候,根据套用的不同类型进行编译,那么,套用不同类型的模板类实际上就是两个不同的类型,也就是说,stack和stack是两个不同的数据类型,他们共同的成员函数也不是同一个函数,只不过具有相似的功能罢了。&amp;lt;img src="https://pic2.zhimg.com/1772de8abdd112a50e533e3c018535a1_b.jpg" data-rawwidth="749" data-rawheight="308" class="origin_image zh-lightbox-thumb" width="749" data-original="https://pic2.zhimg.com/1772de8abdd112a50e533e3c018535a1_r.jpg"&amp;gt;如上图所示,很简短的六行代码,用的是STL里面的stack,stack&amp;amp;lt;int&amp;amp;gt;和stack&amp;amp;lt;char&amp;amp;gt;的默认构造函数和push函数的入口地址是不一样的,而不同的stack&amp;amp;lt;int&amp;amp;gt;对象相同的函数入口地址是一样的,这个也反映了模板类在套用不同类型以后,会被编译出不同代码的现象。

如上图所示,很简短的六行代码,用的是STL里面的stack,stack和stack的默认构造函数和push函数的入口地址是不一样的,而不同的stack对象相同的函数入口地址是一样的,这个也反映了模板类在套用不同类型以后,会被编译出不同代码的现象。

所以模板类的实现,脱离具体的使用,是无法单独的编译的;把声明和实现分开的做法也是不可取的,必须把实现全部写在头文件里面。为了清晰,实现可以不写在class后面的花括号里面,可以写在class的外面。


你可能感兴趣的:(C/C++,语言)