C++模板template

文章详细介绍了C++中的泛型编程,主要通过函数模板和类模板实现。函数模板允许创建通用函数,提高代码复用,而类模板则用于创建通用类。讨论了模板的类型推导、模板具体化以及类模板的使用,包括成员函数的实现和类模板与继承的关系。同时,提到了类模板对象作为函数参数的三种传入方式。
摘要由CSDN通过智能技术生成

C++的另一种编程思想成为泛型编程,主要利用的技术就是模板。
模板不可以直接使用。
模板分为函数模板和类模板:
一、函数模板
建立一个通用函数,其函数返回值类型和形参类型可以不具体确定,用一个虚拟的类型来代表。
模板目的:提高代码复用性,将类型参数化。
语法:

template<typename T>
函数声明或定义

template:声明创建模板
typename:表明其后面的符号是一种数据类型(可用class代替)
T:通用数据类型,名称不一定叫T ,通常是大写字母

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

void test() {
	//使用函数模板,两种方式
	//1、自动类型推导
	int a = 10;
	int b = 20;
	mySwap(a, b);//传入的参数是int型,因此自动推导T为int型
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << endl;
	//2、显示指定类型
	mySwap<int>(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}

注意事项:
1、自动类型推导,必须推导出一致的数据类型T才可以使用。
意思是给T的数据的类型必须一致。
2、模板必须确定出T的数据类型才可以正常使用。

函数模板和普通函数的区别:
普通函数参数传入可以发生隐式类型转换,比如float转int,char转int等,
而函数模板使用自动类型推导时,不可以发生隐式转换;
使用显示指定类型时则可以发生隐式转换。

普通函数和函数模板的调用规则:
函数模板和普通函数同名时,
1、如果函数模板和普通函数都可以实现,优先调用普通函数
2、可以通过空模板参数列表来强制调用函数模板
eg:print<>(a,b);
3、函数模板也可以重载
4、如果函数模板可以产生更好的匹配,优先调用函数模板
更好的匹配:不发生隐式类型转换

模板的具体化解决自定义类型的通用化

template<class T>
bool compare(T& a, T& b) {
	if (a == b) {
		return true;
	}
	else {
		return false;
	}
}

class Person {
	Person(int age, string name) {
		this->m_age = age;
		this->m_name = name;
	}

	int m_age;
	string m_name;
};
int main() {
	Person p1(10, "AA");
	Person p2(10, "AA");
	if (compare(p1, p2)) {//运行时报错,因为对象不能执行“==”操作
		cout << "p1 == p2" << endl;
	}
	else
	{
		cout << "p1 != p2" << endl;
	}
	return 0;
}

加入模板具体化的代码就可以了:

template<> bool compare(Person& p1, Person& p2) {//模板具体化
	if (p1.m_age == p2.m_age && p1.m_name == p2.m_name) {
		return true;
	}
	else {
		return false;
	}
}

二、类模板
作用:建立一个通用类,类中的成员 数据类型可以不具体指定,用一个虚拟的类型表示。

语法:

template<typename T>

template:声明创建模板
typename:表明其后面的符号是一种数据类型(可用class代替)
T:通用数据类型,名称不一定叫T ,通常是大写字母

类模板实例:

template<class NameType,class AgeType>//<class NameType,class AgeType>是模板参数列表
class Person {
public:
	Person(NameType name, AgeType age) {
		this->m_name = name;
		this->m_age = age;
	}
	void show() {
		cout << "name = "<<this->m_name << "age = " << this->m_age << endl;
	}
	NameType m_name;
	AgeType m_age;
};

void test() {
	Person<string, int> p1("Tom", 111);//类模板只有显示推导
	
	p1.show();
}

类模板没有自动类型推导的使用方式;
类模板在模板参数列表中可以有默认参数:

template<class NameType,class AgeType = int>//AgeType默认为int
//创建时
Person<string> p1("Tom", 111);

类模板中成员函数创建时机:调用时再创建

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

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

template<class T>
class myClass {
public:
	T obj;//创建一个T类对象
	void func1() {
		obj.showPerson1();
	}

	void func2() {
		obj.showPerson2();
	}

};

void test() {
	myClass<Person1> p1;
	p1.func1();
	p1.func2();// 运行会报错,但运行前不会报错,因为Person1类中没有showPerson2()这个成员函数,因此说明成员函数在调用时再创建 
}

类模板对象做函数参数:
有三种传入方式:
1、指定传入的类型–直接显示对象的数据类型
2、参数模板化–将对象中的参数变为模板进行传递
3、整个类模板化–将这个对象类型 模板化进行传递
使用比较广泛的第一种传入方式。

template<class T1,class T2>
class Person {
public:
	Person(T1 age, T2 name) {
		this->m_age = age;
		this->m_name = name;
	}

	void showPerson() {
		cout << "age = " << this->m_age << "  name = " << this->m_name << endl; 
	}

	T1 m_age;
	T2 m_name;
};


//1、指定传入的类型--直接显示对象的数据类型
//使用得最广泛
void showPerson1(Person<int,string>&p) {
	p.showPerson();
}

void test1() {
	Person<int, string>p1(1,"P1's name");
	showPerson1(p1);//将类模板对象作为参数传入
}
//2、参数模板化--将对象中的参数变为模板进行传递
template<class T1,class T2>
void showPerson2(Person< T1, T2>&p) {
	p.showPerson();
	cout << "T1 的类型为:" << typeid(T1).name() << endl;
	cout << "T2 的类型为:" << typeid(T2).name() << endl;
}
void test2() {
	Person<int, string>p2(2, "P2's name");
	showPerson2(p2);
}
//3、整个类模板化--将这个对象类型 模板化进行传递
template<class T>
void showPerson3(T &p) {
	p.showPerson();
	cout << "T 的类型为:" << typeid(T).name() << endl;
}
void test3() {
	Person<int, string>p3(3, "P3's name");
	showPerson3(p3);
}

类模板与继承
当子类继承的父类是类模板时,子类在声明时必须指出父类中T的类型。
如果要灵活指定父类中T的类型,子类也要变成类模板。

类模板成员函数类外实现

template<class T1,class T2>
class Person {
public:
	//成员函数类内声明
	Person(T1 name, T2 age);
	void showPerson();

	T1 m_name;
	T2 m_age;
};
//成员函数类外实现
template<class T1,class T2>//要加上类模板参数列表
Person<T1, T2>::Person(T1 name, T2 age) {
	this->m_name = name;
	this->m_age = age;
}
template<class T1, class T2>
void Person<T1,T2>::showPerson() {
	cout << "name = " << this->m_name << "  age = " << this->m_age;
}

类模板的分文件编写问题以及解决
分文件编写一般是把#include、类声明,包括属性和成员函数的声明等放在头文件.h中。
类模板分文件复杂一些,将.h和.cpp的内容放在一起,把文件后缀名改为.hpp(约定叫.hpp)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值