【C++提高篇】—— C++泛型编程之模板基本语法和使用的详解-三、类模板

时间:2025-01-23 07:16:39

3.1 类模板的使用

语法
template< typename T>

template — 声明创建模板
typename — 表面其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母

示例

//类模板
template<class T1, class T2>
class Person{
public:
	Person(NameTypename,AgeTypeage){
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson(){
		cout<< "name:" << this->m_Name << "age:" << this->m_Age <<endl;
	}
public:
	T1 m_Name;
	T2 m_Age;
};
void test01(){
	//类模板没有自动类型推导的使用方式,要指定NameType为string类型,AgeType为int类型
	Person<string,int>P1("孙悟空",999);
	P1.showPerson();
}
int main()
{
	test01();
	system("pause");
	return 0;
}

注意类模板没有自动类型推导的使用方式,要指定类型

3.2 类模板与函数模板的区别

区别
a. 类模板没有自动类型推导的使用方式,只能用显示指定类型方式
b. 类模板在模板参数列表中可以有默认参数
示例

//有默认参数的类模板
template<class T1,class T2=int>
class Person{
public:
	Person(T1 name,T2 age){
		this->mName = name;
		this->mAge = age;
	}
	void showPerson(){
		cout<< "name:" << this->mName << "age:" << this->mAge <<endl;
	}
public:
	T1 mName;
	T2 mAge;
};
//使用
int main()
{
	Person<string>p("猪八戒",999);//类模板中的模板参数列表可以指定默认参数
	//Person<string,int>p("孙悟空",1000);//必须使用显示指定类型的方式,使用类模板
	p.showPerson();
	system("pause");
	return 0;
}

3.3 类模板中成员函数的的创建时机

类模板中成员函数和普通类中成员函数创建时机的区别:
a. 普通类中的成员函数一开始就可以创建
b. 类模板中的成员函数在调用时才创建

示例

总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建

3.4 类模板对象做函数参数

使用:类模板实例化出的对象,向函数传参的方式
一共有三种传入方式
a. 指定传入的类型 — 直接显示对象的数据类型
b. 参数模板化 — 将对象中的参数变为模板进行传递
c. 整个类模板化 — 将这个对象类型模板化进行传递

示例

总结
1.通过类模板创建的对象,可以有三种方式向函数中进行传参
2.使用比较广泛是第一种:指定传入的类型

3.5 类模板与继承

当类模板碰到继承时,需要注意一下几点
a. 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
b. 如果不指定,编译器无法给子类分配内存
c. 如果想灵活指定出父类中T的类型,子类也需变为类模板

示例

总结:如果父类是类模板,子类需要指定出父类中T的数据类型

3.6 类模板成员函数类外实现

学习目标:能够掌握类模板中的成员函数类外实现
示例

总结:类模板中成员函数类外实现时,需要加上模板参数列表

3.7 类模板分文件编写

问题
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决
解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制

示例

总结:主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp

3.8 类模板与友元

类模板配合友元函数的类内和类外实现
a. 全局函数类内实现 - 直接在类内声明友元即可
b. 全局函数类外实现 - 需要提前让编译器知道全局函数的存在
示例

总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别