一个、“经典模式”失败
我们学过C++的人都知道。在C++中组织代码的经典模型是:将函数或类的声明和定义部分分开在不同的文件之中 ,
即一般将声明放在一个.h的头文件里而定义在放在一个.cpp文件之中,当然这的确是写代码的一种非常优良的风格。但问题
是假设将这样的“经典模型”应用到模版上时就会发生连接上错误。
比如:
文件“A.h”
#include"iostream" using namespace std; #pragma once template<typename T> class A { private: T t; public: A(T d) {t = d;} ~A(void){} void fun(); };
文件“A.cpp”
#include "A.h" #include"iostream" using namespace std; template<typename T> void A<T>::fun() { cout<<t<<"这个是A类"<<endl; }
主文件main.cpp:
#include<iostream> #include"A.h" using namespace std; int main() { A<int> a(1); a.fun(); }
将上面的程序编译连接执行,会发现编译通过,但连接会报错。
上述这样的“经典模型”不再适用与C++模版的主要原因是:模版类或模版函数与一般的C++类或函数不同。对于模版
类或模版函数仅仅有在遇到不同类型的应用时才会实例化出详细不同的函数或类,所以上面的程序连接错误的主要原因是
:模版类A未被实例化,编译器会分别的去编译那三个文件。由于A的定义和A的调用分别处在不同的.cpp文件里,所以当
A.cpp被编译时因未见到详细类型调用所以没实例化。而main.cpp在编译时编译器仅仅从A.h看到了A类的声明,所以编译
器会如果程序在别的地方提供了A的详细定义。所以也没有实例化A。
以至于在连接过程中发现A<int>没有被实例化的定
义而终于报错。
二、“包括模型”的出现
“包括模型”攻克了上述问题,即将模版类的定义和声明都写在同一个.h文件就可以。
这样仅仅要主文件包括了这个.h头文件
则在主文件编译时就会从该.h文件里找到模版类或函数的定义从而产生实例化。
比如:文件“A.h”
#include"iostream" using namespace std; #pragma once template<typename T> class A { private: T t; public: A(T d) {t = d;} ~A(void){} void fun() { cout<<t<<"这个是A类"<<endl; } };
主文件“main.cpp”
#include<iostream> #include"A.h" using namespace std; int main() { A<int> a(1); a.fun(); }
能够执行通过。
三、显示实例化
显示实例化的出现主要是为了模版代码的组织形式的更加灵活性,同一时候也是对于“包括模型”的某些缺点的弥补,
在“包括模型”中有一个非常大的不足就是:将全部的代码都写入一个.h头文件里这会明显的添加头文件的开销,且同一时候
对于应用该模版的每个.cpp文件来说都要把此.h文件包括进去,显然这样做会更进一步的使整个程序的开销变的非常
大,所以解决问题的一个办法就是“显示实例化”。
在最上面的那个样例中连接报错的原因是A<int>未被实例化,找不到详细的定义。所以假设我们还是想沿用经得
起历史考验的“经典模型”时。就须要自己去显示实例化。
“显示实例化”的详细形式非常easy:仅仅要在模版定义的.cpp文件里加上一句有显示实例化指示符template引导的须要
实例化实体的声明就可以。
比如:对于最上面的样例:再要在A.cpp中在上以下的声明就可以:
template A<int>;
比如完整样例改动后例如以下:
文件“A.h”
#include"iostream" using namespace std; #pragma once template<typename T> class A { private: T t; public: A(T d) {t = d;} ~A(void){} void fun(); };
文件“A.cpp”
#include "A.h" #include"iostream" using namespace std; template A<int>;//显示实例化 template<typename T> void A<T>::fun() { cout<<t<<"这个是A类"<<endl; }
主文件“mian.cpp”
#include<iostream> #include"A.h" using namespace std; int main() { A<int> a(1); a.fun(); }执行通过!
四、“包括模型”与“显示实例化”的结合
事实上“显示实例化”也有其自己的弊端。那就是对于模版类或模版函数的某一个详细类型的显示实例化必须唯一。不能反复
实例化,这也就是说在程序中你必须自己去跟踪模版的每个实例化,否则就会出错。
这种问题在达到一定规模的大程序中
是相当困难的。所以将“包括模型”与“显示实例化”结合就是取各自之长。能够依据详细问题的要求而任意选择不同的模型。
详细的做法是:任然将模版的定义和声明都分开写在两个不同的文件。但这两个文件都必须是.h的头文件。且定义文件要
用#include包括声明文件。
所以当自己希望使用“包括模型”时,仅仅须要把定义文件.h包括在应用.cpp文件就可以。而当自己须要使用
”显示实例化“时,仅仅须要将声明.h文件包括在应用文件之中,而且同一时候在模版定义.h文件间的需要显示详细的示例可以是实例。
版权声明:本文博客原创文章。博客,未经同意,不得转载。