C++:模板

本文深入介绍了C++中的模板机制,包括函数模板和类模板。函数模板允许创建通用的函数,如`mySwap`,可以用于不同类型的数据交换。类模板则用于创建通用类,如`Person`,可以处理不同类型的姓名和年龄。文章还讨论了模板的自动类型推导、函数模板的调用规则以及类模板的成员函数创建时机,并提供了多个示例展示模板的实际应用。
摘要由CSDN通过智能技术生成
  • 模板就是建立通用的模具,大大提高复用性
  • 特点:
    • 模板不可以直接使用,它只是一个框架
    • 模板的通用并不是万能的
  • C++另一种编程思想为泛型编程,主要利用的技术就是模板
  • C++提供两种模板机制:函数模板类模板

  • 函数模板
    • 作用:建立一个通用的函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
    • 语法:template<typename T>       //函数声明或定义
      • template---声明创建模板
      • typename---其后面的符号是一种数据类型,可以用 class 代替
      • T---通用的数据类型,名称可以替换,通常为大写字母
#include <iostream>

using namespace std;

//两个整型交换
void swapInt(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

//交换两个浮点型
void swapDouble(double& a, double& b)
{
	double tmp = a;
	a = b;
	b = tmp;
}

//特点:
//使用函数模板交换两个数据
template<typename T>	//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用的数据类型
void mySwap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}


int main()
{
	int a = 2;
	int b = 3;
	//两种方式使用函数模板
	//1.自动类型推导
	mySwap(a, b);
	cout << "a= " << a << " b= " << b << endl;

	//显示指定类型
	mySwap<int>(a, b);
	cout << "a= " << a << " b= " << b << endl;
	system("pause");
	return 0;
}

  •  函数模板注意事项
    • 自动类型推导:必须推导出一致的数据类型 T ,才可以使用
    • 模板必须要确定出 T 的数据类型才可以使用
  • 函数模板案例
  • 案例描述:
    • 利用函数封装一个排序的函数,可以对不同数据类型数组进行排序
    • 排序规则从大到小,排序算法为选择排序
    • 分别用char 数组和int 数组进行测试
#include <iostream>

using namespace std;

//交换函数模板
template<typename T>
void mySwap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;

}

//数组排序模板
template<typename T>
void mySelectSort(T arr[],int len)
{
	for (int i = 0; i < len; i++)
	{
		int max = i;	//认定最大值的下标
		for (int j = i + 1; j < len; j++)
		{
			//认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值
			if (arr[j] > arr[max])
			{
				//更新最大值下标
				max = j;
			}
		}
		if (max != i)
		{
			//交换
			mySwap(arr[i], arr[max]);
		}
	}
}

//数组打印模板
template<typename T>
void myPrintArr(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void test()
{
	char charArr[] = "beasfrs";
	int intArr[] = { 3,6,2,4,5,8,9,7,1 };
	int len1 = sizeof(charArr) / sizeof(charArr[0]);
	int len2 = sizeof(intArr) / sizeof(intArr[0]);
	mySelectSort(charArr,len1);
	mySelectSort(intArr, len2);
	myPrintArr(charArr, len1);
	myPrintArr(intArr, len2);
}


int main()
{
	test();
	system("pause");
	return 0;
}

  • 普通函数与函数模板的调用规则
    • 如果函数模板和普通函数都可以实现,优先调普通函数
    • 可以通过空模板参数列表来强制调用函数模板
    • 函数模板也可以发生重载
    • 如果函数模板可以产生更好的匹配,优先调用函数模板 
#include <iostream>

using namespace std;

void myPrint(int a, int b)
{
	cout << "调用普通函数" << endl;
}

template<typename T>
void myPrint(T a, T b)
{
	cout << "调用函数模板" << endl;
}

//重载
template<typename T>
void myPrint(T a, T b,T c)
{
	cout << "调用重载函数模板" << endl;
}

void test()
{
	int a = 10;
	int b = 20;
	myPrint(a, b);

	//通过空模板参数列表,强制调用
	myPrint<>(a, b);

	myPrint(1, 2, 3);

	//更好的匹配,优先调用模板
	myPrint("a", "b");
}

int main()
{
	test();
	return 0;
}

  • 类模板
    • 作用:建立一个通用类,类中成员的数据类型可以不具体制定,用一个虚拟的类型来代表
    • 语法:template<typename T>    +    类
#include <iostream>

using namespace std;

template<class NameType,class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void showInfo()
	{
		cout << "姓名:" << this->name << endl;
		cout << "年龄:" << this->age << endl;
	}
	NameType name;
	AgeType age;
};

void test()
{
	Person<string,int> p("张三", 18);
	p.showInfo();
}

int main()
{
	test();
	return 0;
}

  • 类模板与函数模板的区别
    • 类模板没有自动类型推导的使用方式
    • 类模板在模板参数列表中可以有默认参数
      • template<class NameType,class AgeType = int>
      •     Person<string> p("张三", 18);
  • 类模板中成员函数创建时机
    • 普通类成员函数一开始就可以创建
    • 类模板中的成员函数在调用时才创建
#include <iostream>

using namespace std;

class Person1
{
public:
	void showPerson1()
	{
		cout << "Person1 show" << endl;
	}
};

class Person2
{
public:
	void showPerson2()
	{
		cout << "Person2 show" << endl;
	}
};

template<class T>
class MyClass
{
public:
	void fun1()
	{
		//只要不调用,就不会创建
		obj.showPerson1();
	}
	void fun2()
	{
		//只要不调用,就不会创建
		obj.showPerson2();
	}
	T obj;
};

void test()
{
	MyClass<Person1> mc;
	mc.fun1();
	//mc.fun2();
}

int main()
{
	test();
	return 0;
}

  • 类模板对象做函数参数 
    • 三种传入方式:
      • 指定传入的类型----直接显示对象的数据类型
      • 参数模板化----将对象中的参数变为模板进行传递
      • 整个类模板化----将这个对象类型模板化进行传递
#include <iostream>

using namespace std;

template<class NameType, class AgeType>
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->name = name;
		this->age = age;
	}

	void showInfo()
	{
		cout << "姓名:" << this->name << endl;
		cout << "年龄:" << this->age << endl;
	}
	NameType name;
	AgeType age;
};

//指定传入类型
void printPerson1(Person<string, int>& p)
{
	p.showInfo();
}

//参数模板化
template<class NameType, class AgeType>
void printPerson2(Person<NameType, AgeType>& p)
{
	p.showInfo();
}

//将整个类模板化
template<class T>
void printPerson3(T& p)
{
	p.showInfo();
}

void test()
{
	Person<string , int> p("张三", 18);
	//printPerson1(p);
	//printPerson2(p);
	printPerson3(p);
}

int main()
{
	test();
	return 0;
}

  • 类模板与继承
    • 当子类 继承的父类是一个类模板时,子类在声明的时候,要指定父类中 T 的类型
      • template<class T>
        class Base
        {
        	T m;
        };
        
        
        class Son :public Base<int>
        {
        
        };

    • 如果不指定,编译器无法给子类分配内存
    • 如果想灵活指定父类中 T 的类型,子类也需变为类模板
      • #include <iostream>
        
        using namespace std;
        
        template<class T>
        class Base
        {
        	T m;
        };
        
        template<class T1,class T2>
        class Son :public Base<T2>		//T2是父类的
        {
        	T1 n;
        };
        
        
        void test()
        {
        	Son<int, string> s;
        }
        int main()
        {
        	
        	return 0;
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值