1. 类模板基本概念
类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。
类模板用于实现类所需数据的类型参数化
类模板在表示如数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含的数据类型的影响。
//类模板
template<class NameType,class AgeType>
class Person{
public:
Person(NameType name, AgeType age){
this->mName = name;
this->mAge = age;
}
void PrintPerson(){
cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
void test05(){
//记住:类模板只能显式指定类型,不能自动类型推导
Person<string, int> p("John",30);
p.PrintPerson();
}
2. 类模板做函数参数
//类模板
template<class NameType, class AgeType>
class Person{
public:
Person(NameType name, AgeType age){
this->mName = name;
this->mAge = age;
}
void PrintPerson(){
cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}
public:
NameType mName;
AgeType mAge;
};
//类模板做函数参数
void DoBussiness(Person<string,int>& p){
p.mAge += 20;
p.mName += "_vip";
p.PrintPerson();
}
int main(){
Person<string, int> p("John", 30);
DoBussiness(p);
system("pause");
return EXIT_SUCCESS;
}
3. 类模板派生普通类
//类模板
template<class T>
class MyClass{
public:
MyClass(T property){
this->mProperty = property;
}
public:
T mProperty;
};
//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的
//这样c++编译器才能知道给子类分配多少内存
//普通派生类
class SubClass : public MyClass<int>{
public:
SubClass(int b) : MyClass<int>(20){
this->mB = b;
}
public:
int mB;
};
4. 类模板派生类模板
//父类类模板
template<class T>
class MyClass{
public:
MyClass(T property){
this->mProperty = property;
}
public:
T mProperty;
};
//子类类模板
template<class T>
class SubClass : public MyClass<T>{
public:
SubClass(T b) : MyClass<T>(b){
this->mB = b;
}
public:
T mB;
};
5. 类模板类内实现
//类模板类内实现 函数体在类模板的内部实现
template<class T>
class Person{
public:
//重载左移操作符
friend ostream& operator<<(ostream& out, Person& p){
out << p.mProperty << endl;
return out;
}
//重载普通友元
friend void FriendPerson(Person& p){
cout << p.mProperty << endl;
}
Person(T property){
this->mProperty = property;
}
void PrintPerson(){
cout << this->mProperty << endl;
}
private:
T mProperty;
};
void test(){
Person<int> p(10);
//调用类的成员函数打印
p.PrintPerson();
//重载左移操作符友元函数
cout << p;
//普通友元函数
FriendPerson(p);
}
6. 类模板类外实现
//类模板类内实现 函数体在类模板的内部实现
template<class T>
class Person{
public:
//重载左移操作符
template<class T1> friend ostream& operator<<(ostream& out, Person<T1>& p);
//重载普通友元
template<class T2> friend void FriendPerson(Person<T2>& p);
//构造函数
Person(T property);
//成员函数
void PrintPerson();
private:
T mProperty;
};
//----------类外实现--------------------
template<class T>
Person<T>::Person(T property){
this->mProperty = property;
}
template<class T>
void Person<T>::PrintPerson(){
cout << this->mProperty << endl;
}
//重载左移操作符
template<class T>
ostream& operator<<(ostream& out, Person<T>& p){
out << p.mProperty << endl;
return out;
}
//重载普通友元
template<class T>
void FriendPerson(Person<T>& p){
cout << p.mProperty << endl;
}
int main(){
//编译通过,那么咱们来用用
Person<int> p(10);
//调用成员方法编译通过执行通过
p.PrintPerson();
//调用普通友元函数编译报错无法解析的外部符号
FriendPerson(p);
//调用重载左移操作符编译报错无法解析的外部符号
cout << p;
system("pause");
return EXIT_SUCCESS;
}
7. 类模板头文件和源文件分离问题
Person.h
#ifndef PERSON_H
#define PERSON_H
template<class T>
class Person{
public:
#if 1
//重载左移操作符
template<class T1> friend ostream& operator<<(ostream& out, Person<T1>& p);
//重载普通友元
template<class T2> friend void FriendPerson(Person<T2>& p);
#endif
//构造函数
Person(T property);
//成员函数
void PrintPerson();
private:
T mProperty;
};
#endif
Person.cpp
#include "Person.h"
template<class T>
Person<T>::Person(T property){
this->mProperty = property;
}
template<class T>
void Person<T>::PrintPerson(){
cout << this->mProperty << endl;
}
#if 1
//重载左移操作符
template<class T>
ostream& operator<<(ostream& out, Person<T>& p){
out << p.mProperty << endl;
return out;
}
//重载普通友元
template<class T>
void FriendPerson(Person<T>& p){
cout << p.mProperty << endl;
}
#endif
结论: 编译失败,无法链接的外部符号。
解决方案: 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).
原因:类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。C++编译规则为独立编译。
8. 类模板碰到友元
8.1 类模板碰到普通友元函数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
//声明类模板存在
template<class T> class MyClass;
//声明友元函数模板存在
template<class T> void PrintMyClass(MyClass<T> &ms);
template<class T> ostream &operator<<(ostream &out, MyClass<T> &ms);
template<class T>
class MyClass{
//普通友元函数必须提前声明
friend void PrintMyClass<>(MyClass<T> &ms);
//左移操作符(vs)不需要提前声明,(bcc gcc编译器需要提前声明)
friend ostream &operator<<<>(ostream &out, MyClass<T> &ms);
public:
MyClass();
private:
T mA;
};
template<class T>
MyClass<T>::MyClass(){
mA = 100;
}
template<class T>
void PrintMyClass(MyClass<T> &ms){
cout << ms.mA << endl; //可访问
}
template<class T>
ostream &operator<<(ostream &out, MyClass<T> &ms){
out << ms.mA;
return out;
}
int main(){
MyClass<int> ms;
PrintMyClass(ms);
cout << ms << endl;
return 0;
}
8.2 类模板碰到友元函数模板
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
template<class T>
class MyClass{
//友元函数模板
template<class D> friend void PrintMyClass(MyClass<D> &ms);
template<class D> friend ostream &operator<<(ostream &out, MyClass<D> &ms);
public:
MyClass();
private:
T mA;
};
template<class T>
MyClass<T>::MyClass(){
mA = 100;
}
template<class T>
void PrintMyClass(MyClass<T> &ms){
cout << ms.mA << endl; //可访问
}
template<class T>
ostream &operator<<(ostream &out, MyClass<T> &ms){
out << ms.mA;
return out;
}
int main(){
MyClass<int> ms;
PrintMyClass(ms);
cout << ms << endl;
system("pause");
return EXIT_SUCCESS;
}