C++中可以将模板的思想应用于类,使得类的可以不关注具体所操作的数据类型,而只关注类所需要实现的功能。
C++中的类模板: 提供一种特殊的类以相同的行为处理不同的类型。 在类声明前使用template进行标识。 < typename T >用于说明类中使用的泛指类型 T。
声明的泛指类型 T可用于声明成员变量和成员函数。
编译器对类模板的处理方式和函数模板相同:
编译器从类模板通过具体类型产生不同的类。编译器在声明的地方对类模板代码本身进行编译。编译器在使用的地方对参数替换后的代码进行编译。类模板的应用: 使用具体类型定义对象。
代码举例:
#include <cstdlib>#include <iostream>using namespace std;template<typename T>//类模板 class Operator{public: T add(T a, T b);//修饰成员变量 T minus(T a, T b);};template<typename T>//修饰成员函数 T Operator<T>::add(T a, T b)//要加上<T>{ return a + b;}template<typename T> T Operator<T>::minus(T a, T b){ return a - b;}int main(int argc, char *argv[]){ Operator<int> op1; //必须加上类型名 Operator<double> op2; cout<<op1.add(5, 4)<<endl; cout<<op1.minus(4, 5)<<endl; cout<<op2.add(1.3, 0.01)<<endl; cout<<op2.minus(0.01, 1.3)<<endl; cout << "PRess the enter key to continue ..."; cin.get(); return EXIT_SUCCESS;}类模板中对于定义成员函数的cpp文件,编译时发现全都为函数模板,就会只会检查语法是否正确,不会生成可执行代码。等到了要调用这个函数的时候,编译器会第二次编译这个函数,但是头文件中如果只包含了类定义的内容,没有包含成员函数的定义,就会调用失败,程序报错。
因此,需要把类中的成员函数的定义和类定义放在一起。
或者,在main文件中包含成员函数的定义的cpp或hpp文件,同时在成员函数定义文件中包含类定义的头文件,这样就全部被包含了。
#include "成员函数定义文件.cpp"#include "成员函数定义文件.hpp"在模板类外部定义成员函数的实现时,需要加上template < typename T > 的声明。
举例说明:
//类数组模板 类定义 头文件 Array.h#ifndef _ARRAY_H_#define _ARRAY_H_template<typename T> //定义数组类 class Array{private: int mLength; T* mSpace;public: Array(int length); Array(const Array& obj); int length(); ~Array(); T& operator[](int i); Array& operator= (const Array& obj); bool operator== (const Array& obj); bool operator!= (const Array& obj);};#endif//类数组模板 成员函数定义 头文件 Array.hpp#ifndef _ARRAY_DEF_H_#define _ARRAY_DEF_H_ //加上宏保护#include "Array.h" //包含类类定义的头文件 template<typename T>Array<T>::Array(int length)//构造函数,注意 Array<T>::{ if( length < 0 ) { length = 0; } mLength = length; mSpace = new T[mLength];}template<typename T>Array<T>::Array(const Array& obj)//构造函数 { mLength = obj.mLength; mSpace = new int[mLength]; for(int i=0; i<mLength; i++) { mSpace[i] = obj.mSpace[i]; }}template<typename T>int Array<T>::length()//获取数组大小 { return mLength;}template<typename T>Array<T>::~Array() //析构函数 { mLength = -1; delete[] mSpace;}template<typename T>T& Array<T>::operator[](int i)//重载 [] 操作符{ return mSpace[i];}template<typename T>Array<T>& Array<T>::operator= (const Array<T>& obj)//重载 = 操作符{ delete[] mSpace; mLength = obj.mLength; mSpace = new int[mLength]; for(int i=0; i<mLength; i++) { mSpace[i] = obj.mSpace[i]; } return *this;}template<typename T>bool Array<T>::operator== (const Array<T>& obj)//重载 == 操作符 { bool ret = true; if( mLength == obj.mLength ) { for(int i=0; i<mLength; i++) { if( mSpace[i] != obj.mSpace[i] ) { ret = false; break; } } } else { ret = false; } return ret;}template<typename T>bool Array<T>::operator!= (const Array& obj)//重载 != 操作符 { return !(*this == obj);}#endif//main文件 main.cpp#include <cstdlib>#include <iostream>#include "Array.hpp" //包含成员函数定义的文件 using namespace std;int main(int argc, char *argv[]){ Array<int> ai(5); //类成员变量为int类型 for(int i=0; i<ai.length(); i++) { ai[i] = i + 1; cout<<ai[i]<<endl; } Array<double> ad(10); //类成员变量为char类型 for(int i=0; i<ad.length(); i++) { ad[i] = (i + 1) / 100.0; cout<<ad[i]<<endl; } cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS;}类模板可以被特化: 用 template <> 声明一个类时,表示这是一个特化类。
特化类模板的意义: 当类模板在处理某种特定类型有缺陷时,可以通过类模板的特化来克服处理这种特定类型带来的不足。
注意: 编译器优先选择特化类生成对象。
代码举例:
#include <cstdlib>#include <iostream>using namespace std;template<typename T>class Test{public: T test(T v) { cout<<"T test(T v)"<<endl; cout<<"sizeof(T) = "<<sizeof(T)<<endl; return v; }};template<> //特化 class Test<int>{public: int test(int v) { cout<<"int test(int v)"<<endl; cout<<"sizeof(int) = "<<sizeof(int)<<endl; return v; }};int main(int argc, char *argv[]){ Test<int> t1; cout<<t1.test(1)<<endl; cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS;}新闻热点
疑难解答