• 学习C++第二十二课--类模版概念与函数模版的定义、调用笔记


    一、类模板概念

    类模板和函数模板不一样,编译器不能为类模板推断模板参数。所以为了使用类模板,必须在模板名后面用尖括号“<>”提供额外信息,这些信息其实就是对应着模板参数列表里的参数。例如我们已经熟悉的vector,这里面的vector是类模板,尖括号里的int就理解成模板参数,通过这个模板参数指出容器vector中所保存的元素类型。

    C++中为什么会出现类模板这个概念呢?当然这也与函数模板一个道理,一个容器,如 vector 容器 ,可以往里面放整型元素、实型元素 、字符串 ,甚至还可以装其他类对象。为了避免出现很多重复的代码,引入了类模板没然后通过模板参数,往这个类模板中传递不同的类型或者非类型参数,从而实现同一套代码,可以应付不同的数据类型,这样,代码就显得精简和通用多了。

    二、类模板的定义

    类模板(也称为模板类)定义的一般形式如下:

    1. template <typename形参名1,typename形参名2,..,typename形参名n>
    2. class 类名
    3. {
    4.    //......
    5. }

    请注意,template后面的<>中如果有多个模板参数,参数之间要用逗号分隔。

    用类模板定义对象的写法:

    类模板名 <真实类型参数表> 对象名(构造函数实参表);

    演示一下,写一个比较正规的类模板,可以考虑模拟 C++ 标准库提供的 vector ,写一个 自己的 vector ,起名为 myvector。以往实现一个类的候可以写一个 文件来进行类定义,然后再写. cpp 文件实现类的各种成员函数.但是对于类模板,因为实例化具体类的时候必须有类模板的全部信息,包括类模板中成员函数的函数体具体内容等,所以,类模板的所有信息,不管是声明,还是实现等内容必须写到一个.h文件中去,其他的要到类模板的源程序文件(如 .cpp文件) 只要#include 这个类模板的.h文件即可

    创建一个myvector.h文件,内容文件:

    1. using namespace std;
    2. template<typename T>
    3. class myvector
    4. {
    5. public:
    6. typedef T* myiterator;
    7. public:
    8. myvector();
    9. myvector& operator=(const myvector&);
    10. public:
    11. myiterator mybegin();
    12. myiterator myend();
    13. };
    14. #endif // !__STUDENT_H__

    在.cpp文件中这样写:

    1. using namespace std;
    2. template<typename T>
    3. myvector::myvector()//实例化构造函数
    4. {
    5. }

    在main主函数中,要给这个类模板用尖括号<>提供明白无误的模板参数(也就是提供容器中的元素类型),所以加入以下代码:

    1. int main()
    2. {
    3. myvector <int> tmpvector1; //T被替换成int
    4. myvector <double> tmpvector2;//T被替换成double
    5. myvector tmpvector3;//T被替换成string
    6. return 0;
    7. }

    main函数中的 myvector tmpvector1;、 myvector tmpvector2和myvector tmpvector3;都是实例化类模板,编译器会生成一个具体的类型,这里就是int类型。也就是说,每种类型,编译器都会生成一个不同的类。

    注意:myvector 是类模板名,不是一个类型名(或者说是一个残缺的类型名),类模板是用来实例化类型的。所以myvector <int> myvector <double> myvector <string>才是真正的类型名。所以可以看出,一个通过类模板实例化了的类类型总会用尖括号包含着模板参数。

    三、类模板的成员函数

    类模板成员函数可以写在myvector.h的vector类模板声明中,这种写在类模板声明中的成员函数就被隐式声明为内联函数。

    当然,类模板的成员函数声明也可以写在vector类模板声明中,而在vector类模板声明之外实现。

    下面在myvector.h的myvector类模板中,增加如下成员函数的声明:

    1. public:
    2. myfunc();

    在myvector.cpp文件中这样定义成员函数:

    1. template<typename T>
    2. void myvector::myfunc()//实例化构造函数
    3. {
    4.     cout << "类模板成员函数!" << endl;
    5. }

    有一点值得注意, 一个类模板虽然里面可能有很多成员函数但是当实例化模板之后, 如果后续没有使用到某个成员函数则这个成员函数是不会被实例化的换句话说,个实例化的模板,它的成员只有在使用的时候才会被实例化〈程序员编写的代码中出现了调用成员函数的代码)

    四、类模板名字的使用

    在类模板myvector中有一个赋值运算符的重载代码:

    myvector& operator=(const myvector&);

    上面的赋假运算符重载返回一个myveclor 的引用请注,在类模板内部,可以接使用类模板名,并不需要在类模板名后模板参数.因为在类模板定义内部,如果没提供类模板参数,编译器会假定类模板名带与不带模板参数等价(也就是 myvector 等价于myvector < T >).

    myvector& operator=(const myvector&);//等价:myvector& operator=(const myvector&);

    但是需要注意的是:

    如果在类模板定义之外实现这个赋值运算符重载,需要这样写:

    1. template<typename T>
    2. myvector& myvector::operator=(const myvector&)//第一个表示返回的是一个实例化了的myvector,第三个不是必加
    3. {
    4. return *this;
    5. }

    五、非类型模板参数的使用

    模板参数并不局限于类型,普通的值也能作为模板参数,也就是非类型模板参数。

    myvector类模板中是一个类型模板参数,那么看看非类型模板参数怎么用,下面创建一个类模板来演示。

    在.h中声明一个类模板带非类型模板参数,如下:

    1. template<typename T,int size = 10>
    2. class myarray
    3. {
    4. private:
    5. T arr[size];
    6. };

    在.cpp的main函数中,增加如下代码:

    myarray<int,100> tmparr;

    当然,也可以使用默认的非类型模板参数值,这样就可以少传递一个模板参数:

    myarray<int> tmparr; //size默认值为10

    同时也要注意,myarray类模板里面有两个模板参数,在类定义之外书写成员函数实现的时候也要注意写法。首先,在类模板内增加一个用public修饰的myfunc成员函数的声明。代码如下:

    1. public:
    2. void myfunc();

    在.cpp文件中定义myarray成员函数的实现:

    1. template<typename T, int size>
    2. void myarray::myfunc()
    3. {
    4. cout << "size" << endl;
    5. }

    在main函数中,加入如下代码来做一下调用:

    1. int main()
    2. {
    3. myarray<int>tmparr1;
    4. tmparr1.myfunc(); //10
    5. myarray<int,100>tmparr2;
    6. tmparr2.myfunc(); //100
    7. return 0;
    8. }

    注意:这种非类型的模版参数,参数的类型还是有一定限制的,如下定义会报错:

    (1)浮点型一般不能作为非类型模板参数。

    1. template<typename T,double size>
    2. class myarray
    3. {
    4. ......
    5. }

    (2)类类型也不难作为非类型模板参数。

    1. class A{
    2. ......
    3. };
    4. template<typename T,A size>
    5. class myarray
    6. {
    7. ......
    8. };

    2022.08.11结。

  • 相关阅读:
    Bootstrap学习从一个模板开始
    RabbitMq消息队列
    深度学习卫星遥感图像检测与识别 -opencv python 目标检测 计算机竞赛
    6.SSM-SpringBoot
    【LeetCode - 每日一题】2594. 修车的最少时间(23.09.07)
    【RocketMq 系列】RocketMq 消息重试机制、死信队列
    mysql根据单一字段去重
    提高内外部协同效率的软件
    【赛码网刷题】动态规划之上台阶
    【牛客刷题-算法】NC34 不同路径的数目(一) | 动态规划、组合数解法
  • 原文地址:https://blog.csdn.net/euxnijuoh/article/details/126290402