上一篇讲了c++的函数模板,类模板是在比类更高级层次上的抽象,可以用类模板来创建类。简单的说,类模板就是一个抽象的类。
类模板、类及对象的关系
1、类模板定义的语法格式如下:
template <class T1, class T2, …>
class 类名
{
类成员声明
}
类模板定义中各部分的意义和函数模板定义中各部分的意义几乎相同。
2、代码实例
以下是一个类模板的实例,CStore为类模板,在主函数main()中调用。
Store.h中写入:
#pragma once
#include <iostream>
using namespace std;
template <class T> //仓库类
class CStore
{
public:
CStore(void);//默认形式(无形参)的构造函数
~CStore(void);
T GetElem(void);//提取数据函数
void PutElem(T x);//存入数据函数
private:
T item;//item 用于存放任意类型的数据
int haveValue;//haveValue标记item是否已被存入内容
};
Store.cpp中写入:
#include "StdAfx.h"
#include "Store.h"
//以下实现各成员函数
//注意:模板类的成员函数,若在类外实现,则必须是模板函数,即所有函数
// 均以CStore <T>修饰!
template <class T>
CStore<T>::CStore(void):haveValue(0) //参数初始化表初始化haveValue元素为0
{
}
template <class T>
CStore <T>::~CStore(void)
{
}
template <class T>
T CStore<T>::GetElem(void)
{
if(haveValue==0)
{
cout<<"No item present!"<<endl;
//exit(1);
}
return item;
}
template <class T>
void CStore<T>::PutElem(T x)
{
haveValue++;
item=x;
}
Test.cpp中写入:
// test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
#include "Store.h"
#include "Store.cpp"
struct Student//结构体Student
{
int id;//学号
float gpa;//平均分
};
void test()
{
Student g={1000,23};
CStore<int> S1,S2;
CStore<Student> S3;
CStore<double> D;
S1.PutElem(3);
S2.PutElem(-7);
cout<<S1.GetElem()<<" "<<S2.GetElem()<<endl;
Sleep(1000);
S3.PutElem(g);
cout<<"The studnet id is "<<S3.GetElem().id<<endl;
cout<<"The studnet gpa is "<<S3.GetElem().gpa<<endl;
Sleep(1000);
D.PutElem(3.1415);
cout<<"Retrieving object D ";
cout<<D.GetElem()<<endl;
Sleep(1000);
}
int _tmain(int argc, _TCHAR* argv[])
{
test();
cout<<"测试完毕!"<<endl;
Sleep(10000);
system("pasue");
return 0;
}
注:C++中,我们习惯将类的定义放在.h文件,而将类的实现放在.cpp文件中。而在使用这个类的时候包含它的头文件即可。但是这样使用会产生这样一种错误:
1>test.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall CStore<int>::~CStore<int>(void)" (??1?$CStore@H@@QAE@XZ),该符号在函数 "void __cdecl test(void)" (?test@@YAXXZ) 中被引用
在网上查了一些大虾写的博客,终于找到原因了:
在类模板的声明和定义中把.h与.cpp分离
现总结一条:在使用类模板技术时,可在.h中实现,也可在.h和.cpp中分开实现,若用.h实现,不要在文件中加入非类模板代码,可避免重写定义错误.
这组错误信息和project中不加入Store.cpp的错误信息一样,即没有CTpl<char>的实现代码
我们把Store.cpp包涵到main.cpp中,问题解决。
3、几点说明
1)类模板中,表示一个类是模板名加<模板参数>,如在一个类模板定义中用到另一个类模板时,采用以下方式定义。:
Template <class T>
Class TRect{
public:
TRect();
Get();
……
Private:
Tcoord<T> p1; // TCoord <T>表示一个类。
……
};
2)如果构造函数声明和实现分开时,构造函数实现的函数名应该是如下形式:
模板名称<模板参数>::模板名称() //注意域前和域后不一致
对应,成员函数实现时格式如下:
模板名称<模板参数>::函数名()
3)类模板的实现和声明分开时,每个带模板参数的成员函数实现时,必须定义模板参数,参数名可以和申明不同。如:
template <class TT> //必须定义参数名,但是模板参
//数名可以不同,这里T变为了TT
TT TCoord <TT>::getx()
{
return x;
}