【C++】提高 -- 类模板

news2025/1/11 20:03:26

目录

一、类模板的作用

二、类模板的语法

三、类模板的例子

四、类模板和函数模板的区别

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

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

七、类模板与继承

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

九、类模板分文件编写

十、类模板与友元

十一、类模板案例


一、类模板的作用

建立一个通用类,类中成员、数据类型可以不具体指定,用一个虚拟的类型来代表

二、类模板的语法
template<typename T>
//类
三、类模板的例子
//类模板
template<class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this.m_Name = name;
        this.m_Age = age;
    }

    void showPerson()
    {
        cout << "姓名:" << this->m_name << "年龄:" << this->m_Age << endl;
    }
    
    NameType m_Name;
    AgeType m_Age;
};

void test01()
{
    person<string,int> p1 ("悟空",99);
    p1.showPerson();
}
四、类模板和函数模板的区别

①类模板没有自动类型推导的使用方法

②类模板在模板参数列表中可以有默认参数

//类模板与函数模板的区别
template<class NameType, class AgeType = int>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this.m_Name = name;
        this.m_Age = age;
    }

    void showPerson()
    {
        cout << "姓名:" << this->m_name << "年龄:" << this->m_Age << endl;
    }
    
    NameType m_Name;
    AgeType m_Age;
};

void test01()
{
    //类模板没有自动类型推导的使用方式
    person<string,int>p1("悟空",99);//可以编译
    person p1 ("悟空",99);//不可以编译

    p1.showPerson();
}

void test02()
{
    //类模板在模板参数列表中可以有默认参数
     person<string>p2("八戒",9);//在模板中定义了该属性默认是一个int形

    p2.showPerson();
}
五、类模板中成员函数创建时机

在普通类中成员函数一开始就创建了;在类模板中成员函数在调用时才创建

class Person1
{
public:
    void showPerson1()
    {
        cout << "Person1 show" << endl;
    }
};

class Person2
{
public:
    void showPerson2()
    {
        cout << "Person2 show" << endl;
    }
};

template<class T>
class Myclass
{
public:
    T obj;
    
    //类模板中的成员函数
    void func1()
    {
        obj.showPerson1();
    }

    void func2()
    {
        obj.showPerson2();
    }
}

当前函数代码段可以成功编译不报错,因为类模板中成员函数在调用时才创建所以编译时没调用不报错,obj并没有确定类型

void test01()
{
    MyClass<Person1>m;
    m.func1();
    m.func2();
}

在上述代码段中添加该测试用例,编译器会报错,无法调用func2。

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

类模板实例化出的对象向参数传参的方式一共有3种:

①指定传入的类型 -- 直接显示对象的数据类型 【最常用的方法】

②参数模板化 -- 将对象中的参数变为模板进行传递

③整个类模板化 -- 将这个对象类型 模板化进行传递

template<class T1,class T2>
class Person
{
public:
    
    Person(T1 name,T2 age)
    {
        this.m_Name = name;
        this.m_Age = age;
    }

    void showPerson
    {
        cout << "姓名:" << this.m_Name << endl;
        cout << "年龄:" << this.m_Age << endl;
    }

    T1 m_Name;
    T2 m_Age;
}

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

void test01()
{
    Person<string,int>p("悟空",800);
    printPerson1(p);
}


//参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p)
{
    p.showPerson();
    //如何查看模板类型
    cout << "T1类型:" << typeid(T1).name() << endl; 
    cout << "T2类型:" << typeid(T2).name() << endl; 
}


void test02()
{
    Person<string,int>p("八戒",120);
    printPerson2(p);
}


//整个类模板化
template<class T>
void printPerson3(T &p)
{
    p.showPerson();
    cout << "T数据类型:" << typeid(T).name << endl;
    //会显示Person类型
}

void test03()
{
    Person<string,int>p("唐僧",100);
    printPerson3(p);
}
七、类模板与继承

注意事项:

①当子类继承的父类是一个类模板时,子类在声明的时候要指定出父类中T的类型

②如果不指定,编译器无法给子类分配内存

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

class Son :public Base //此方法是错误的,必须要知道父类中的T的数据类型才能继承给子类
{
    
};

class Son :public Base<int>//此方法正确
{
    
};

void test01()
{
    T1 obj;
}

③如果想灵活指定出父类中T的类型,子类也需变为类模板

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

template<class T1,class T2>
class Son2 :public Base<T2>
{
public:

    Son2()
    {
        cout << "T1类型:" << typeif(T1).name << endl;
        cout << "T2类型:" << typeif(T2).name << endl;
    }

    T1 obj;
};

void test02()
{
    Son2<int, char>S2;
}
八、类模板成员函数类外实现
//类内声明,类外实现
template<class T1,class T2>
class Person
{
public:
    
    Person(T1 name,T2 age);
    
    void showPerson();
 
    T1 m_Name;
    T2 m_Age;
};

//函数模板类外实现的构造函数
teemplate<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
        this.m_Name = name;
        this.m_Age = age;
}

//成员函数类外实现
teemplate<class T1,class T2>
void Person<T1,T2>::showPerson()
{
        cout << "姓名:" << this.m_Name << endl;
        cout << "年龄:" << this.m_Age << endl;
}
九、类模板分文件编写出现的常见问题与解决方法

问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决方法:

①直接包含.cpp源文件

②将声明和实现写到同一个文件中,并更改后缀名为.hpp【hpp仅是约定的名字,可改】

第一步在头文件中添加新建项

第二步添加头文件 -- Person.h

其中Person.h内容为:

#pragma once
#include <iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age);

    void showPerson();

    T1 m_Name;
    T2 m_Age;

};

第三步在源文件中添加 -- Person.cpp

Person.cpp内容为:

#include "Person.h"

template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
    this.m_Name = name;
    this.m_Age= age;

}

template<class T1, class T2>
Person<T1,T2>::showPerson()
{
    cout << "姓名:" << this.m_Name << "年龄:" << this.m_Age << endl;
}

第四步在需要使用的文件中输入以下代码:

部分编译器会出现报错无法正常生成代码[因为类模板中的成员函数是在调用时创建,编译器无法正确识别该代码],解决方法有以下:

解决方案1:将改行代码修改为 #include "Person.cpp",让编译器将.h和.cpp两个文件都阅读一次后再做接下来的解析,但是不建议使用该方式,会使二进制包变大

#include <iostream>
using namespace std;
#include "Person.h"//解决方案1:将改行代码修改为 #include "Person.cpp",让编译器将.h和.cpp两个文件都阅读一次后再做接下来的解析,但是不建议使用该方式,会使二进制包变大

void test01()
{
    Person<string,int>p("ming",18);
    p.showPerson();
}

解决方案2:将.h文件中的内容和.cpp文件中的内容写一个.hpp文件中放在头文件中,声明和实现都在一个文件中【伪份文件编写】

相关内容可参考文章https://blog.csdn.net/HXG2006/article/details/128754137?ops_request_misc=&request_id=&biz_id=102&utm_term=.hpp%E5%92%8C.cpp%E5%8C%BA%E5%88%AB&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-128754137.142^v100^pc_search_result_base4&spm=1018.2226.3001.4187

#include <iostream>
using namespace std;
#include "Person.hpp"//解决方案2
void test01()
{
    Person<string,int>p("ming",18);
    p.showPerson();
}

十、类模板与友元

全局函数类内实现:直接在类内声明友元即可

全局函数类外实现:需要提前让编译器知道全局函数的存在

//通过全局函数打印Person信息

//提前让编译器知道Person类存在
template<class T1,class T2>
class Person;

//全局函数不用加作用域
template<class T1,class T2>
friend void printPerson2(Person<T1,T2> p)
{
    cout << "类外实现 -- 姓名:" << p.m_Name << "类外实现 -- 年龄;" << p.m_Age << endl;
}

template<class T1, class T2>
class Person
{
    //全局函数类内实现
    friend void printPerson(Person<T1,T2> p)
    {
        cout << "姓名:" << p.m_Name << "年龄;" << p.m_Age << endl;
    }
    
    //全局函数类外实现
    //需要加一个空模板的参数列表
    //如果全局函数是类外实现需要让编译器提前知道这个函数的存在
    friend void printPerson2<>(Person<T1,T2> p);  

public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

private:
    T1 m_Name;
    T2 m_Age;
};

十一、类模板案例

实现以一个通用的数组类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2064968.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

日撸Java三百行(day31:整数矩阵及其运算)

目录 前言 一、基本属性与方法 二、getter与setter方法 三、矩阵相加与矩阵相乘方法 1.矩阵相加 2.矩阵相乘 四、数据测试 五、完整的程序代码 总结 前言 从今天开始&#xff0c;我们就要踏上图论的学习之路了。第一天&#xff0c;我们先简单热个身&#xff0c;构造一…

手持气象站:便携式、高精度设备

在科技日新月异的今天&#xff0c;气象观测技术正以前所未有的速度发展&#xff0c;从传统的地面观测站、高空探测到卫星遥感&#xff0c;每一步都极大地拓宽了我们对天气的认知边界。而在这股科技浪潮中&#xff0c;手持气象站作为一种便携式、高精度的气象监测设备&#xff0…

Ps:首选项 - 文件处理

Ps菜单&#xff1a;编辑/首选项 Edit/Preferences 快捷键&#xff1a;Ctrl K Photoshop 首选项中的“文件处理” File Handling选项卡允许用户精确控制 Photoshop 的文件保存行为和兼容性选项。这些设置非常重要&#xff0c;尤其在处理大文件或与其他软件协作时&#xff0c;可…

用Zipkin在分布式系统追踪收集和查看时间数据

Zipkin是一个开源的分布式追踪系统&#xff0c;它帮助收集、存储和展示实时的数据&#xff0c;以便于定位微服务架构中的延迟问题。以下是Zipkin的核心组件和工作流程的介绍&#xff0c;以及如何在Java中使用Spring Cloud Sleuth与Zipkin集成的案例。 Zipkin的核心组件&#x…

那些久远的开发语言(COBOL、Pascal、Perl等)还有市场吗

旧的开发语言 在旧的开发语言中&#xff0c;除了Combo和BASIC之外&#xff0c;还有一些其他曾经流行或具有重要历史意义的编程语言&#xff0c;例如&#xff1a; FORTRAN&#xff1a;1957年诞生&#xff0c;是第一个编译型语言&#xff0c;主要用于科学和工程计算 。LISP&…

RabbitMQ高级用法

&#x1f4a5; 该系列属于【SpringBoot基础】专栏&#xff0c;如您需查看其他SpringBoot相关文章&#xff0c;请您点击左边的连接 目录 一、发送者的可靠性 1. 生产者重试机制 2. 生产者确认机制【return和confirm机制】 &#xff08;1&#xff09;开启生产者确认 &#x…

ARCGIS XY坐标excel转要素面

1、准备好excel 坐标 excel文件转为csv才能识别&#xff0c;CSV只能保留第一个工作表并且&#xff0c;不会保留格式。 2、在ArcGis中导入XY事件图层 创建XY事件图层 图层要素赋对象ID 将导入的图层导出为先新的图层&#xff0c;这样就给每个要素附加了唯一的值 选择点集转线…

python模块03 --ddt数据驱动

自动化框架设计思想&#xff1a; (1) 数据驱动测试&#xff1a;即英文单词Data-Driven Testing&#xff0c;简称DDT。 (2) 关键字驱动测试&#xff1a;即英文单词Keyword-Driven Testing&#xff0c;简称KDT。 (3) 业务流程测试&#xff1a;即英文单词Business Process Tesi…

AI大模型:开源与闭源的激烈交锋与未来展望

在人工智能的浩瀚星空中&#xff0c;大模型作为技术的璀璨明珠&#xff0c;正引领着行业变革的浪潮。从最初的闭源垄断到如今的开源与闭源并驾齐驱&#xff0c;AI大模型的发布趋势、竞争格局以及技术演进&#xff0c;无不彰显着这一领域的蓬勃生机与无限可能。本文将深入探讨开…

大白话讲微服务的灾难性雪崩效应

讲在前面&#xff0c;为什么微服务需要有熔断等策略呢&#xff1f;今天我们用大白话来讲讲微服务的灾难性雪崩效应&#xff0c;熔断策略就是解决雪崩效应的有效解决方案。 什么是灾难性雪崩效应&#xff1f; 假设我们有两个访问量比较大的服务A和B&#xff0c;这两个服务分别依…

深度理解指针(2)

hello各位小伙伴们&#xff0c;关于指针的了解我们断更了好久了&#xff0c;接下来这几天我会带领大家继续我们指针的学习。 数组名的理解 我们首先来看一段代码&#xff1a; #include<stdio.h> int main () {int arr[10] {1,2,3,4,5,6,7,8,9,10};printf("arr …

汇编语言:标志寄存器ZF、PF、SF、CF、OF、DF、IF、AF

CPU内部的寄存器中&#xff0c;一种特殊的寄存器&#xff08;对于不同的CPU&#xff0c;个数和结构可能都不同&#xff09;&#xff0c;具有以下3种作用。 &#xff08;1&#xff09;用来存储相关指令的某些执行结果 &#xff08;2&#xff09;用来为CPU执行相关指令提供行为…

科技大通缩

BCG 增长份额矩阵的经典“摇钱树”象限。 来源&#xff1a;Understanding the BCG Growth Share Matrix and How to Use It &#xfeff; S 曲线的暴政 要了解这如何应用于科技行业&#xff0c;我们需要了解 S 曲线现象。 成功产品带来的价值通常会经历 S 曲线增长&#xff…

Python办公自动化 生成房产销售的分析报告【2】

学好办公自动化&#xff0c;走遍天下都不怕&#xff01;&#xff01; 办公三件套Excel、Word 和PPT。前面已经学习过如何处理excel数据以及批量自动生成word文档。 今天主要是利用前面学习的python-pptx模块并且根据房屋销售信息生成分析报告。报告总共6页内容&#xff0c;包括…

C++进阶之智能指针

一、为什么需要智能指针 下面我们先分析一下下面这段程序有没有什么内存方面的问题&#xff1f;提示一下&#xff1a;注意分析MergeSort 函数中的问题。 int div() {int a, b;cin >> a >> b;if (b 0)throw invalid_argument("除0错误");return a / b; }…

机器人学——逆向运动学(机械臂)

正/逆运动学对比 求解 求解目标 Reachable workspace 与 Dexterous workspace Subspace 解的数目 多重解 解的选择 求解方法 栗子一 x,y,fai已知&#xff0c;求解theta(1,2,3)的具体数值 几何法 余弦定理定义&#xff1a;对于任意三角形ABC&#xff0c;设其三个内角分别为…

Behind the Code:Ewald Hess 带你一起深度解读链上能源与外交

2024 年 9 月 14 日&#xff0c;《Behind the Code: Web3 Thinkers》第二季第九集上线。在本集中&#xff0c;Ewald Hess 深入剖析了区块链技术在推动能源市场变革中的关键作用。长期以来&#xff0c;传统能源行业因垄断和低效饱受批评&#xff0c;但随着 Bitcoin 和 Ethereum …

企业入驻西安国际数字媒体产业园的十大好处

在当今数字化飞速发展的时代&#xff0c;企业的发展需要依托创新的平台和资源的整合。西安国际数字影像产业园&#xff0c;作为数字产业的引领者&#xff0c;为入驻企业提供了众多独特的优势和机遇。 好处一&#xff1a;产业集聚效应。西安国际数字影像产业园汇聚了众多数字媒体…

字符函数内存函数———C语言

字符分类函数 头文件&#xff1a; ctype.h 函数功能iscntrl判断字符是否为控制字符isspace判断字符是否为空白字符&#xff08;空格&#xff0c;换页、换行、回车、制表符或垂直制表符&#xff09;isdigit判断字符是否为十进制数字isxdigit判断字符是否为十六进制数字(0-9)(a…

二分+划分型dp,CF 360B - Levko and Array

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 B - Levko and Array 二、解题报告 1、思路分析 最小化最大值&#xff0…