Fork me on GitHub

C++:类模板知识回顾

概述

类的私有、公有、类继承有时并不能满足我们的开发需求,尤其是将类作为容器(泛型编程)使用时,因此类模板在C++随之衍生。相关概念也会在下文中一一阐述~

模板类的定义与使用

template <class T1,class T2>
class Pair
{
private:
	T1 a;
	T2 b;
public:
	Pair() {};
	Pair(const T1& aval, const T2& bval) : a(aval), b(bval) {};
	T1& first();
	T2& second();
	T1 first() const { return a; };
	T2 second() const { return b; };

};

template是模板声明,<>中就是类模板参数,你可以理解为形参列表。class T1class相当于参数声明,可以看出和函数模板其实是一个套路,只不过函数模板参数声明为typename

模板类深入:非类型参数

类模板常用作容器,这是因为在进行模板声明时,形参列表中也不必全是class,也可以是 int等,这种做法称之非类型参数或表达式参数。总结就是类模板参数声明接受枚举,整型,类,常量表达式,引用或指针,不能是变量而应该是常量!

template <class Type,int n/*非类型参数/表达式*/>
class ArrayTP
{
private:
	Type ar[n];

public:
	ArrayTP() {};
	~ArrayTP() {};
	Type& operator[](int i);
	Type& operator[](int i) const;

};

模板类深入:多功能性

好家伙,初次学习多功能性直接给我干懵逼了,类模板其实使用起来灵活性非常大,再加个多功能性只能说人麻了。但是具体去看时发现这里说的多功能性并不是引入了新的关键字或者是新语法,而是说类模板具备常规类得所有用法,比如作为基类、递归、也可以使用非类型参数进行声明,也可以当作参数用于其他类或类模板。具体比如下面这样引入多个参数:

template <class T1,class T2>
class Pair
{
private:
	T1 a;
	T2 b;
public:
	Pair() {};
	Pair(const T1& aval, const T2& bval) : a(aval), b(bval) {};
	T1& first();
	T2& second();
	T1 first() const { return a; };
	T2 second() const { return b; };

};

嘿嘿,是不是和定义得代码一摸一样~

模板类深入:具体化

具体化就是对类模板进行实现。实现方式有有隐式实例化,显式实例化,隐式具体化三种。

隐式实例化

就是使用类模板定义一个对象但在不需要之前都不进行实现,但是当你new或者调用这个对象时会将这个类实现(开辟内存空间)。

Pair <string,valarray<double>>  P2;

显式实例化

如果我们定义模板时候知道我们必定会使用到某一种模板,那就可以进行显式实例化,这种做法和隐式实例化作用一样,编译时不会对类对象进行实现。需要注意显式实例化和类模板的定义必须处于同一个文件!

template Pair<string,string> P3;

显式具体化

这种做法和函数模板得具体化一毛一样。当你想针对某一组形参列表进行不同的操作时,就可以利用显式具体化。

template <class T1> 
class Pair
{
    //接口和对象
}

//显式具体化
template <> Pair<string>
class Pair
{
    //接口和对象
}

除了完全体得显式具体化,还有部分显式具体化,也就是说在定义类模板时直接将某些参数固定,比如:

template <class T1,int/*部分具体化*/> 
class Pair
{
    //接口和对象
}

当用类模板定义类对象时,编译器会调用具体化程度最高得那个,这一点和函数具体化类似。总之,函数得实例化大家可以灵活运用,但一定要切记这里只是实例化,不是实现!

模板类深入:成员模板、参数模板

我们前面提到了,类模板得多功能性提到可以将类模板作为另一个类模板的模板参数,也称之为参数模板。而将类模板作为其他类得成员,这种做法称之为成员模板。具体大家看下下面代码就明白了:

成员模板

template <class T1,class T2>
class Pair
{
private:
	T1 a;
	T2 b;
    
    //成员模板
 	template <class V>
	//模板类
	class hold
	{
	private:
		V val;
	public:
		hold(V v = 0) :val(v) {};
		void show()  const { cout << this->val << endl; }
		V value() const { return this->val; }
	};
	hold <T1> q;//根据pair传进来的类型确定
    
public:
	Pair() {};
	Pair(const T1& aval, const T2& bval) : a(aval), b(bval) {};
	T1& first();
	T2& second();
	T1 first() const { return a; };
	T2 second() const { return b; };
};

参数模板

template <template<class T2> T1>//参数模板
class Pair
{
private:
	T1<int> a;
	T1<double> b;
   
public:
	Pair() {};
	Pair(const T1& aval, const T2& bval) : a(aval), b(bval) {};
	T1& first();
	T2& second();
	T1 first() const { return a; };
	T2 second() const { return b; };
};

模板类深入:友元

模板也可以声明为友元,模板类的友元的主要目的还是为了外部的参数能够访问类的私有成员。模板类的友元声明有三种:非约束友元、约束模板友元、非约束模板友元

//模板声明
template <class U>  void reports1(U& u);
template <class V>  void counts1();
template<class T1, class T2> void show(T1& t1, T2& t2);

template <class T>
class Hasfriend
{
private:
	T item;
	static int ct;
public:
	Hasfriend(const T& i) :item(i) { ct++; };
	~Hasfriend() { ct--; };
	//非模板友元函数,类模板中声明常规的友元函数
	friend void counts();
	//约束模板友元函数,友元函数的具体化
	friend void report1<>(Hasfriend<T>& hf);
	friend void counts1<int>();
	//非约束模板友元函数:友元函数的模板化,也就是声明一个  友元_模板成员
	template<class T1,class T2>
	friend void show(T1 &t1,T2 &t2);
	//
};

总结

类模板的基础概念和基本使用并没有什么难度,但是实际开发时会出现很多问题,比如模板参数引入不正确,栈指针不正确等会导致极其严重的后果。因此关于类中继承、友元、模板等使用最好还是多去实际项目中总结学习,这样才能完全掌握类的使用,实际上本白的工作并不会涉及到类,Cnaoe也是只在介绍相关Capl接口时给说明了下成员有那些可以访问,因此C++函数及之前的部分已经足够自己工作中用了。但有时间最好还是主动去尝试运用类的概念去搭建服务器和客户端,这样对于工作和代码理解都会有很大的帮助,也给重复性的工作找点乐子~

 

posted @ 2022-12-14 23:23  张一默  阅读(43)  评论(0编辑  收藏  举报