C++:类模版的定义与实例化


定义格式

template<class T1, class T2, ..., class Tn> 
class 类模板名
{
// 类内成员定义 
};
使用类模版构建动态顺序表
template <class T>
class SeqList {
	T* m_data;
	size_t m_size;
	size_t m_capacity;

	void checkCapacity();
public:
	SeqList(size_t size = 0, size_t capacity = 10) :
		m_data(new T[capacity]),
		m_size(size),
		m_capacity(capacity)
	{
	}

	T& operator [](size_t i)
	{
		return m_data[i];
	}

	void push_back(const T& src);
	void pop_back();

	int size();

	~SeqList();
};

// 在类中声明,在类外定义。 
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
void SeqList<T>::checkCapacity() {
	if (m_size == m_capacity) {
		m_capacity *= 2;

		m_data = (T*)realloc(m_data, sizeof(T) * m_capacity);
		/*T* newSpace = new T[m_capacity];

		for (i = 0; i < m_size; i++) {
			newSpace[i] = m_data[i];
		}
		delete[] m_data;
		m_data = newSpace;*/
	}
}

template <class T>
void SeqList<T>::push_back(const T& src) {
	checkCapacity();

	m_data[m_size++] = src;
}

template <class T>
void SeqList<T>::pop_back() {
	if (m_size == 0) {
		return;
	}
	m_size--;
}

template <class T>
int SeqList<T>::size() {
	return m_size;
}

template <class T>
SeqList<T>::~SeqList() {
	if (m_data) {
		delete[] m_data;
	}
	m_size = m_capacity = 0;
}

注意:SeqList不是具体的类,是编译器根据被实例化的类型生成具体类的模具

类模版实现切记:

  1. 在类模版的实现过程中,最好不要将class与函数实现拆成两个文件。 直接在.h文件中将函数实现还有类做完成。

  2. 如果拆成两个文件,必须将两个文件全部include到main函数的文件中,要不然就找不到对应的实现代码,也就无法生成一个实体版的可执行的函数。

实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

代码示例:

int main(){ 
	// SeqList类名,SeqList<int>才是类型 
	SeqList<int> sl;

	sl.push_back(1);
	sl.push_back(2);
	sl.push_back(3);
	sl.pop_back();
	SeqList<double> s1;
	s1.push_back(3.1415);
	s1.push_back(1.618);
	for (int i = 0; i < sl.size(); ++i)
	{
		cout << sl[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < s1.size(); ++i)
	{
		cout << s1[i] << " ";
	}
	cout << endl;

	return 0;
}

代码生成图
在这里插入图片描述

类模板的特化

全特化

全特化即是将模板参数列表中所有的参数都确定化。

template<class T1, class T2>
class Data
{
public:
    Data() {cout << "Data<T1, T2>" << endl;}
private:
	T1 _d1;
	T2 _d2; 
};

template<>
class Data<int, char>
{
public:
    Data() {cout<<"Data<int, char>" <<endl;}
private:
	int _d1;
	char _d2; 
};

void TestVector()
{
    Data<int, int> d1;  // 调用 Date
    Data<int, char> d2; // 调用 Date<int, char>
}
偏特化

任何针对模版参数进一步进行条件限制设计的特化版本。

比如对于以下模板类:

template<class T1, class T2>
class Data
{
public:
    Data() {cout<<"Data<T1, T2>" <<endl;}
private:
	T1 _d1;
	T2 _d2; 
};

偏特化有以下两种表现方式:

  • 部分特化

将模板参数类表中的一部分参数特化。

// 将第二个参数特化为int 
template <class T1> 
class Data<T1, int>
{
public:
    Data() {cout<<"Data<T1, int>" <<endl;}
private:
    T1 _d1;
	int _d2; 
};
  • 参数更进一步的限制

偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。

//两个参数偏特化为指针类型
template <typename T1, typename T2> 
class Data <T1*, T2*>
{
public:
    Data() {cout<<"Data<T1*, T2*>" <<endl;}
private:
    T1 _d1;
	T2 _d2; 
};

//两个参数偏特化为引用类型
template <typename T1, typename T2> 
class Data <T1&, T2&>
{
public:
    Data(const T1& d1, const T2& d2)
        : _d1(d1)
		, _d2(d2) 
	{
		cout<<"Data<T1&, T2&>" <<endl;
	}
private:
    const T1 & _d1;
    const T2 & _d2;
};

void test2 ()
{
	Data<double , int> d1;	// 调用特化的int版本
    Data<int , double> d2;	// 调用基础的模板
	Data<int *, int*> d3;	// 调用特化的指针版本
	Data<int&, int&> d4(1, 2);	// 调用特化的引用版本 
}

知识点习题

  1. 类模板的使用实际上是类模板实例化成一个具体的__________。

A 类
B 函数
C 模板类
D 对象

正确答案:

A

答案解析

类模板就是把类中的数据分离出来,作为一个类的描述。C++编译器根据类模板和特定的数据类型来产生一个类,类模板就是一个抽象的类。

  1. 代码可以通过编译吗?如果不能应该如何修改?
template<class T> class Foo{
        T tVar;
    public:
        Foo(T t) : tVar(t) { }
};

template<class T> class FooDerived:public Foo<T>
{
};

int main()
{
    FooDerived<int> d(5);
    return 0;
}

A. 代码可以正确通过编译。
B. 编译错误,FooDerived是一个继承模板类的非模板类,它的类型不能改变。
C. 编译错误,tVal变量是一个不确定的类型。
D. 编译错误,可以在FooDerived类中添加一个构造函数解决问题。

正确答案: D

答案解析:

当基类构造函数需要外部传递参数才能进行初始化时,派生类必须显式定义构造函数,为基类传递参数;基类如果不需要传递或者可以不传递参数,派生类可以不用显式定义构造函数。


如有不同见解,欢迎留言讨论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值