C++面向对象程序设计 - 类模板

        C++允许使用函数模板,对于功能相同而数据类型不同的一些函数,不必一一定义各个函数,可以定义一个可以对任何类型变量进行操作的函数模板,在调用函数时,系统会根据实参的类型,取代函数模板中的类型参数,得到具体函数。

        对于类的声明来说,也有同样的问题;有时两个或多个类,其功能是相同的,仅仅是数据类型不同。显然这种重复性工作是不必要的,C++在发展后期增加了模板(template)的功能,提供了解决这类的途径;可以声明一个通用的类模板,它可以有一个或多个虚拟的类型参数,创建可以重用的组件,这些组件可以处理多种数据类型,而不仅仅是单一的数据类型。

一、类模板定义

        声明类模板时要增加一行:

template <class 类型参数名>

        由于类模板包含类型参数,因此又称为参数化的类。如果说类是对象的抽象,对象是类的实例,则类模板是类的抽象,类是类模板的实例。复用类模板可以建立含各种数据类型的类。例如定义一个获取各种类型数组中最大小、最小值的类,代码如下:

#include <iostream>
#include <array>
using namespace std;

template<class T, size_t size>
class Compare_array{
	private:
		array<T, size> Arr;    // 使用std::array来存储数组
	public:	
		// 获取函数
		Compare_array(T (&arr)[size]){    //接收一个数组的引用
            // 使用std::copy来复制数组内容
			std::copy(std::begin(arr), std::end(arr), std::begin(this->Arr));
		}
		// 获取最大值
		T get_max(){
			T max = Arr[0];
			for(size_t i = 0; i < size; i++){
				if(Arr[i] > max) max = Arr[i];
			}
			return max;
		}
		// 获取最小值
		T get_min(){
			T min = Arr[0];
			for(size_t i = 0; i < size; i++){
				if(Arr[i] < min) min = Arr[i];
			}
			return min;
		}
};

int main(){
	// int型数组
	int nums_int[] = { 100, 150, 38, 15, 90, 70, 66};
    // 实例化时须提供数据类型和数组大小
	Compare_array <int, sizeof(nums_int) / sizeof(nums_int[0])> ca1(nums_int);
	cout <<"int array max:" <<ca1.get_max() <<", min:" <<ca1.get_min() <<endl;
	
	// float型数组
	float nums_float[] = { 10.05f, 15.5f, 38.15f, 15.22f, 90.18f, 70.9f, 66.85f};
	Compare_array <float, sizeof(nums_float) / sizeof(nums_float[0])> ca2(nums_float);
	cout <<"float array max:" <<ca2.get_max() <<", min:" <<ca2.get_min() <<endl;
	
	// double型数组
	double nums_double[] = { 12343, 644311, 55327, 846445, 98875, 343677};
	Compare_array <double, sizeof(nums_double) / sizeof(nums_double[0])> ca3(nums_double);
	cout <<"double array max:" <<ca3.get_max() <<", min:" <<ca3.get_min() <<endl;
	return 0;
}

        运行结果可见,通过类模板定义类Compare_array,可以处理各数据类型的数组,获取最大值和最小值,如下图:

       对于上述代码几个细节说明:

  1. 在C++中,类模板的成员数组需要指定大小,所以这里使用std::array容器来代替;
  2. 由于数组不能通过赋值操作来复制,所以这里使用std::copy来逐个元素地复制;
  3. 构造函数形参应该是一个对数组的引用,需要包含size_t size作为模板参数;
  4. Compare_arr中std::array<T, size>作为私有成员,它在编译时根据size参数确定大小,所以类模板实例化时要提供数组的大小。

二、函数模板

        相必很多人已经学过函数模板了,上述代码存在很多重复代码,咱们用函数模板将程序再优化一下,顺便复习下函数模板相关知识。代码如下:

#include <iostream>
#include <array>
using namespace std;

template<class T, size_t size>
class Compare_array{
	private:
		array<T, size> Arr;    // 使用std::array来存储数组
	public:	
		// 获取函数
		Compare_array(T (&arr)[size]){    //接收一个数组的引用
            // 使用std::copy来复制数组内容
			std::copy(std::begin(arr), std::end(arr), std::begin(this->Arr));
		}
		// 获取最大值
		T get_max(){
			T max = Arr[0];
			for(size_t i = 0; i < size; i++){
				if(Arr[i] > max) max = Arr[i];
			}
			return max;
		}
		// 获取最小值
		T get_min(){
			T min = Arr[0];
			for(size_t i = 0; i < size; i++){
				if(Arr[i] < min) min = Arr[i];
			}
			return min;
		}
};

// 定义函数模板 显示最大和最小值
template<typename N, size_t S>
void showMaxMin(N (&arr)[S], const char* typeName){
	// 实例对象
	Compare_array <N, S> ca(arr);
	// 显示最大和最小值
	cout <<typeName <<" max:" <<ca.get_max() <<", min:" <<ca.get_min() <<endl;
}

int main(){
	// int型数组
	int nums_int[] = { 100, 150, 38, 15, 90, 70, 66};
    showMaxMin(nums_int, "int");
	
	// float型数组
	float nums_float[] = { 10.05f, 15.5f, 38.15f, 15.22f, 90.18f, 70.9f, 66.85f};
	showMaxMin(nums_float, "float");
	
	// double型数组
	double nums_double[] = { 12343, 644311, 55327, 846445, 98875, 343677};
	showMaxMin(nums_double, "double");
	return 0;
}

        和前面还是一样的,但代码看起来比之前简洁了许多,优化掉了许多不必要且重复性较高的代码。结果如下图:

三、数组引用的区别

        想必有些人已发现了Compare_array构造函数形参时和showMaxMin函数中形参都是数组的引用,但在第一个示例中Compare_array实例时必须要传入数组大小,而showMaxMin函数中却不需要。

        Compare_array类模板使用了两个模板参数:T(数组元素的类型)和size(数组的大小)。当实例化Compare_array类时,需要为这两个模板参数提供具体的值。这是因为在类的内部,std::array<T, size>成员变量Arr的大小需要在编译时确定。由于C++标准库中的std::array是一个固定大小的容器,其大小必须在模板实例化时明确指出。

        showMaxMin函数模板也是用了两个模板参数:N(数组元素的类型)和S(数组的大小)。当传递一个数组给showMaxMin函数时,编译器会自动推断出数组元素的类型N和数组的大小S,作为函数模板的参数。这是通过模板参数的类型推导(type deduction)机制实现的。

        所以在showMaxMin函数内部,创建了一个Compare_array<N, S>类型的对象ca,并将传递进来的数组arr作为构造函数。此时由于N和S已被推断出来,可以直接使用它们来实例化Compare_array类。

        总的来说,Compare_array类需要显示提供大小参数,是因为它内部std::array成员需要在编译时确定大小。而showMaxMin函数模板能够自动获取数组大小,是因为编译能够根据传递给函数的实际数组参数进行类型推导。

四、归纳

        归纳以上的内容,可以这样声明和使用类模板:

1)先写一个实际的类。

2)将此类中准备改变的类型名改用一个自己指定的虚拟类型名。

3)在类声明前面加入一行,格式为:

template<class 虚拟类型参数>

        示例代码如下:

template<class T, size_t size>
class Compare_array{ 
    // 略...
}

4)用类模板定义对象时用以下形式:

类模板名 <实际类型名> 对象名;

类模板名 <实际类型名> 对象名(实参列表)

        示例代码如下:

Compare_array <int, array_length> ca1(nums_int);

5)如果在类模板外定义成员函数,应写成类模板形式:

template<class 虚拟类型参数>

函数类型 类模板名 <虚拟类型参数> :: 成员函数名(函数形参表列){ ...... }

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值