20. 类模板

一、什么是类模板

类模板用于建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型来代替。它的语法格式如下:

cpp 复制代码
template<typename T>

类模板与函数模板相比主要有两点区别:1) 类模板没有自动类型推导的方式。2) 类模板在模板参数中可以有默认参数。

cpp 复制代码
#include <iostream>

using namespace std;

// 类模板中可以使用默认参数
template<class NameType, typename AgeType=int>
class Person
{
public:
    NameType name;
    AgeType age;

    Person(void) {}
    Person(NameType name, AgeType age) : name(name), age(age) {}

    void showPerson(void)
    {
        cout << "{name: " << name << ", age: " << age << "}" << endl;
    }
};

int main(void)
{
    // 指定NameType为string,AgeType默认为int
    Person<string> p1("Sakura", 10);
    p1.showPerson();

    return 0;
}

类模板中的成员函数并不是一开始就创建的,而是在模板调用时再生成的。

二、类模板对象做函数参数

类模板对象也可以作为函数的参数,总共有三种方式传入:

  • 指定传入的类型 ------ 直接显示对象的数据类型。
  • 参数模板化 ------ 将对象中的参数变为模板进行传递。
  • 整个类模板化 ------ 将这个对象类型模板化进行传递。
cpp 复制代码
#include <iostream>

using namespace std;

// 类模板中可以使用默认参数
template<class NameType, typename AgeType=int>
class Person
{
public:
    NameType name;
    AgeType age;

    Person(void) {}
    Person(NameType name, AgeType age) : name(name), age(age) {}

    void showPerson(void)
    {
        cout << "{name: " << name << ", age: " << age << "}" << endl;
    }
};

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

// 2、参数模板化
template <typename NameType, typename AgeType>
void printPerson2(Person<NameType, AgeType> &p)
{
    p.showPerson();
}

// 3、这个类模板化
template<typename T>
void printPerson3(T &p)
{
    p.showPerson();
}

int main(void)
{
    Person<string, int> p("Sakura", 10);
    printPerson1(p);
    printPerson2(p);
    printPerson3(p);

    return 0;
}

三、类模板与继承

当子类继承的父类是一个类模板时,子类在声明的时候,要指出父类中 T 的类型。如果不指定,编译器无法给子类分配内存。如果想要灵活指定出父类父类中的 T 的类型,子类也需要变成类模板。

cpp 复制代码
#include <iostream>

using namespace std;

template<typename T>
class SuperClass
{
public:
    T a;
};

// 子类继承模板类,必须知道父类中T类型
class SubClass1 : public SuperClass<string>
{

};

// 如果想要灵活指定父类中T类型,则需要使用模板类
template<typename T1, typename T2>
class SubClass2: public SuperClass<T1>
{
    T2 b;
};

int main(void)
{
    SubClass1 subClass1;
    SubClass2<string, int> subClass2;

    return 0;
}

四、类模板成员函数类外实现

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

新建一个 person.hpp 文件用来保存类的声明和方法。

cpp 复制代码
#pragma once
#include <iostream>

using namespace std;

// 类模板中可以使用默认参数
template<class NameType, typename AgeType=int>
class Person
{
public:
    NameType name;
    AgeType age;

    Person(void);
    Person(NameType name, AgeType age);

    void showPerson(void);
};

在包含 main() 函数的文件中包含刚才定义的头文件,然后使用。

cpp 复制代码
#include <iostream>
// 这里不要包含头文件要包含源文件
// #include "person.hpp"

using namespace std;

int main(void)
{
    Person<string> p1("Sakura", 10);
    p1.showPerson();

    return 0;
}

五、类模板与友元

修改 person.hpp 文件中内容。

cpp 复制代码
#pragma once
#include <iostream>
#include <cstring>

using namespace std;

template<typename NameType, typename AgeType>
class Person;

template<typename NameType, typename AgeType>
void showPerson(Person<NameType, AgeType> p);

// 类模板中可以使用默认参数
template<class NameType, typename AgeType=int>
class Person
{
    // 加空模板的参数列表
    /// 如果全局函数是类外实现的,需要让编译器提前知道这个函数的存在
    friend void showPerson<>(Person<NameType, AgeType> p);

private:
    NameType name;
    AgeType age;

public:
    Person(void);
    Person(NameType name, AgeType age);
};

// 类模板的构造函数类外实现
template<typename NameType, typename AgeType>
Person<NameType, AgeType>::Person(void) {}

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

// 全局函数做友元类外实现
template<typename NameType, typename AgeType>
void showPerson(Person<NameType, AgeType> p)
{
    cout << "{name: " << p.name << ", age: " << p.age << "}" << endl;
}

修改包含 main() 函数的文件中的内容。

cpp 复制代码
#include <iostream>
#include "person.hpp"

using namespace std;

int main(void)
{
    Person<string> p1("Sakura", 10);
    showPerson(p1);

    return 0;
}
相关推荐
智者知已应修善业34 分钟前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
Trouvaille ~38 分钟前
【Linux】应用层协议设计实战(一):自定义协议与网络计算器
linux·运维·服务器·网络·c++·http·应用层协议
CSCN新手听安44 分钟前
【linux】高级IO,I/O多路转接之poll,接口和原理讲解,poll版本的TCP服务器
linux·运维·服务器·c++·计算机网络·高级io·poll
CSCN新手听安1 小时前
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型
linux·服务器·网络·c++·tcp/ip·json
m0_736919101 小时前
C++中的委托构造函数
开发语言·c++·算法
小小小小王王王1 小时前
洛谷-P1886 【模板】单调队列 / 滑动窗口
c++·算法
历程里程碑2 小时前
Linux 库
java·linux·运维·服务器·数据结构·c++·算法
Sheep Shaun2 小时前
如何让一个进程诞生、工作、终止并等待回收?——探索Linux进程控制与Shell的诞生
linux·服务器·数据结构·c++·算法·shell·进程控制
小龙报2 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
石去皿2 小时前
【嵌入式就业6】计算机组成原理与操作系统核心机制:夯实底层基础
c++·面试·嵌入式