C++ 泛型编程:类模板

类模板基本语法

// 定义
template<class T>
class Base
{
	T m1;
};

// 调用
Base<int> base;

类模板与函数模板的区别

  • 类模板没有自动类型推导的使用方式,必须显示指定类型
  • 类模板在模板参数列表中可以有默认参数

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

  • 普通类中的成员函数,一开始就可以创建
  • 类模板中的成员函数在调用时才创建

类模板对象做函数参数

  • 指定传入的类型(最常用)
  • 参数模板化
  • 整个类模板化
#include<iostream>
using namespace std;

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

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

	NameType m_name;
	AgeType m_age;
};

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

// 参数模板化
template<class T1, class T2>
void showPerson2(Person<T1, T2>& p)
{
	p.showPerson();
}

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

int main()
{
	Person<string, int> p("张三", 999);
	showPerson1(p);
	showPerson2(p);
	showPerson3(p);
	return 0;
}

类模板与继承

  • 当父类是类模板时,子类声明时要指定父类中的模板参数类型
  • 如果不指定,编译器无法分配内存
  • 如果想灵活指定父类中的模板参数类型,子类就必须也变为类模板
#include<iostream>

using namespace std;

template<class T>
class Base
{
	T m1;
};

// 子类声明中指定父类中的模板类型
class Son1 : public Base<int>
{
public:
	void show()
	{
		cout << "Son 1 is created" << endl;
	}
};

// 将子类也变为模板类
template<class T1, class T2>
class Son2 :public Base<T2>
{
	T1 m2;

public:
	void show()
	{
		cout << "Son 2 is created" << endl;
	}
};

int main()
{
	Son1 s1;
	s1.show();

	Son2<int, char> s2;
	s2.show();
	return 0;
}

类模板成员函数类外实现

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "person is shown" << endl;
}

类模板份文件编写

需要解决类模板中成员函数在调用是才创建,因此编译器可能链接不到的问题。解决方案如下:

  • 将头文件和源文件合并成一个 .hpp 文件 (推荐)
  • 直接包 include 文件(.cpp 文件)

类模板和友元

  • 全局函数,类内实现(推荐)
  • 全局函数,类外实现(很复杂,不推荐)
template<class NameType, class AgeType>
class Person
{
	friend void showPerson(Person<NameType, AgeType> &p)
	{
		cout << "name: " << p.m_name << " age: " << p.m_age << endl;
	}

public:
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}

private:
	NameType m_name;
	AgeType m_age;
};