C++模板和模板的特化,模板的扩展和智能指针------(14)

news2024/9/28 19:21:10

模板

概念

模板的作用是实现类型通用,降低代码的冗余度
模板可以为一种算法定义不同类型的版本

实现机制:

复制代码使用类型参数突破类型的限制,丧失一定的类型安全
模板需要实例化才能使用,实例化由编译器完成

模板的分类

函数模板
函数模板就是带类型参数的函数,函数的返回值,形参,局部变量都可以使用类型参数,函数模板支持类型推断(形参)。
rust复制代码函数模板 -----> 实例化 -----> 函数
编译

类模板

类模板就是带类型参数的类,类的成员变量,成员函数…可以使用类型参数,类模板不支持类型推断。
rust复制代码类模板 -----> 实例化 -----> 类 -----> 实例化 -----> 对象
编译 运行

模板的使用

函数模板

语法:
arduino复制代码//函数模板的声明
template<typename T/类型参数/…>
返回值类型 函数模板名(形参列表)
{
…//可以使用T作为类型
}

//函数模板的调用
函数模板名<类型…>(实参);
//如果函数模板的类型参数可以通过实参来判断,传递的类型可以省略

练习:
使用函数模板实现一个数组的排序,实现数组元素类型的通用
arduino复制代码void mysort(int *arr,int n);

类模板
语法:
arduino复制代码//类模板的声明
template <typename T/类型参数/…>
class 类模板名{
//…类中可以直接使用T类型
};

//类模板的使用
类模板名<类型…> 对象;
//类模板不支持类型推断

模板的特化
如果模板第某些特殊类型的行为需要重新定义,此时可以进行模板的特化。
函数模板的特化
语法:
arduino复制代码template <>
返回值类型 函数模板名<特化类型…>(参数列表)
{
//…重定义特化类型的行为
}

//编译器在对函数模板实例化时,如果有特化模板,有限选择特化的模板实例化
//函数模板不允许特化一部分参数,必须全特化

类模板的特化(全类特化)
语法:
arduino复制代码template <>
class 类模板名<特化类型…>{
//…类中的内容重定义位特化类型的行为
};

练习:
为排序类模板实现const char *的特化
类模板的成员特化
对于类模板而言,既可以进行全类特化,也可以只针对部分与特化类型相关的成员函数进行特化。成员函数特化时要保持特化接口和原通用模板一致。
语法:
arduino复制代码//类外进行成员特化
template <>
返回值类型 类模板名<特化类型…>::成员函数名(形参列表)
{
//…使用特化类型重定义函数的行为
}

类模板的局部特化
针对有多个类型参数的类模板,可以只特化其中一部分参数,编译器优先选择特化程度最高的版本。
特化一部分参数
arduino复制代码template <T1,T2,T3>
class xxx{…}

//局部特化
template <T1,T2>
class xxx<T1,T2,int>{…}

template
class xxx<T1,double,int>{…}

xxx<char,double,int> a; ------ 选择第三个版本进行实例化
xxx<char,long,int> b; ------- 选择第二个版本进行实例化
xxx<char,long,float> c; ------ 选择第一个版本进行实例化

//对于有多个类型参数的类模板,可以对部分参数进行特化
//编译器优先选择特化程度最高的版本

特化类型参数之间的关系
arduino复制代码template <T1,T2,T3>
class xxx{…}

//局部特化
template <T1,T2>
class xxx<T1,T2,T2>{…}

template
class xxx<T1,T1,T1>{…}

//对于有多个类型参数的类模板,可以对类型参数的关系进行特化
//编译器优先选择特化程度最高的版本

针对指针和数组类型的特化
arduino复制代码template <T1,T2,T3>
class xxx{…}

//局部特化

template <T1,T2,T3>
class xxx<T1*,T2*,T3*>{…}

template <T1,T2,T3>
class xxx<T1[],T2[],T3[]>{…}

//对于有多个类型参数的类模板,可以针对指针和数组类型进行特化
//编译器优先选择特化程度最高的版本

作业:

1.使用函数模板和类模板(函数对象)实现二分查找,同时为函数模板实现const char *的特化,类模板实现const char *的成员(查找的成员函数)特化。


模板参数的默认值,非类型参数和模板参数

模板参数的默认值

1.类模板的参数可以有默认值,有默认值的类型参数必须靠右
  如果实例化不提供参数的类型,就使用默认值 
2.右边类型参数的默认值可以是左边的类型参数  

类模板的非类型参数

1.类模板可以接收非类型参数
2.非类型参数只能是常量,常量表达式,常属性的变量
3.非类型参数也可以有默认值
4.函数模板也可以接收非类型参数和默认值     

以下了解的可以了实际开发可能用不到

模板的模板参数

模板除了可以接收类型参数和非类型参数以外,也可以接收模板作为参数,语法如下:

template <template <typename T> class xxx>
class Crab{
    //...可以使用参数类模板,传入的模板保持统一    
};

模板成员

模板可以作为类模板或类的成员/友元,STL的实现使用了该语法

1.类模板成员
    类模板实例化的类型参数可以来自于外部类模板,也可以直接指定。

2.函数模板成员
    函数模板实例化的类型可以来自于外部类模板或者直接指定,也支持类型推断
    
3.函数模板和类模板作为友元
    如果友元使用了所在类模板的类型参数,属于约束性友元模板
    否则属于非约束型友元模板      

类模板的继承

类继承类模板

语法:

template <typename T>
class BaseA{
public:
    //......
private:
    T data;        
};

//类继承类模板
class Derived:public BaseA<int>{
    //......
};

类模板继承类

语法:

class BaseA{
public:
    //......
private:
    int data;        
};

//类模板继承类
template <typename T>
class Derived:public BaseA{ 
public:
    //.....
private:
    T data2;    
};

类模板继承类模板

语法:

template <typename T>
class BaseA{
public:
    //......
private:
    T data;        
};

//类模板继承类模板
template <typename N>
class Derived:public BaseA<N>{ 
public:
    //.....
private:
    N data2;    
};

继承中使用模板参数

语法:

template <typename T>
class Derived:public T{
    //......    
};

模板的递归实例化

所谓的模板的递归实例化就是使用类模板实例化后作为参数继续实例化本模板

MyArray<int> arr;
MyArray<MyArray<int>> arr;//递归实例化
MyArray<MyArray<MyArray<int>>> arr;//递归实例化

模板的划分

在实际的C++开发中,我们会将类的声明(模板的声明)写在头文件,类/类模板中的函数实现写在源文件,由于模板的实例化是在编译时完成的,所以必须把模板的声明和实现写在一个编译单元中,此时需要使用模板的划分来实现。

可以在模板声明的头文件中用以下语法将实现加进来

#include "xxx.cpp"

练习:

将1search.cpp的类模板实现模板的划分。

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

int main()
{
    A *pa = NULL;
    
    pa->show();
}

注意:可以使用类类型的空指针去调用成员函数,因为成员函数不属于对象,也不存储在对象中,存储在代码段,调用成员函数只需要找到成员函数的地址即可。如果成员函数中访问了成员变量,就会发生段错误。

智能指针

将指针对象模板化实现了类型的通用,构成智能指针。

根据智能指针 拷贝/赋值 处理的不同,可以分为三种实现形式

1.拷贝/赋值时分配新的地址空间,拷贝原指针指向的内容
2.拷贝/赋值时将右边的空间和地址传递给左边,右边会失去原来的地址空间
3.拷贝/赋值时共享地址空间,同时增加一个引用计数(记录使用地址空间的对象个数)
  当引用技术为0释放地址空间

image-20220721230240207

C++预定义了智能指针,可以直接使用,智能指针有4种,介绍其中3种,使用它们需要添加头文件memory

//C++98加入 C++11弃用 C++17移除
auto_ptr ------- 使用方法2实现(只能一个对象记录地址空间)

//C++11添加
unique_ptr ------ 方法2实现,禁止传递的语法
shared_ptr ------ 方法3实现,采用引用计数

智能指针对象销毁时会自动释放记录的地址空间,很大程度上避免了内存泄漏的发生。

作业:

将模板成员的代码实现模板的划分

附加:用户输入两个字符串,编写代码求出两个字符串的最长公共子串

kkkhellowebye
ghsasabyehellod

===>hello
/*02-求最长公共子串*/
#include <iostream>
​
using namespace std;
​
//暴力求解
string getLCS(const string &str1,const string &str2)
{
    //记录最长子串在str1中的起始位置和长度
    size_t max_start = 0,max_len = 0;
​
    for(size_t i=0;i<str1.length();i++){
        for(size_t j=0;j<str2.length();j++){
            //计算当前最长公共子串
            size_t k,l;
            for(k=i,l=j;k<str1.length()&&l<str2.length();k++,l++){
                if(str1.at(k)!=str2.at(l))
                    break;
            }
            //记录最长长度的公共子串
            if(k-i>max_len){
                max_len = k-i;
                max_start = i;
            }
​
        }
    }
​
    return str1.substr(max_start,max_len);
}
​
//矩阵法求解
string getLCS1(const string &str1,const string &str2)
{
    //记录最长子串在str1中的结束位置和长度
    int max_end = 0,max_len = 0;
​
    //创建比较矩阵
    int **arr = new int *[str1.length()];
    for(size_t i=0;i<str1.length();i++){
        arr[i] = new int[str2.length()];
        for(size_t j=0;j<str2.length();j++){
            //比较字符,将比较结果写入矩阵
            if(str1.at(i)==str2.at(j)){//赋值  左上角+1
                //如果左上角不存在
                if(i==0||j==0)
                    arr[i][j] = 1;
                else
                    arr[i][j] = arr[i-1][j-1]+1;
​
                //记录最长长度和此时str1中最后一个字符的位置
                if(arr[i][j]>max_len){
                    max_len = arr[i][j];
                    max_end = i;
                }
            }
            else{
                arr[i][j] = 0;
            }
        }
    }
​
    //释放空间
    for(size_t i=0;i<str1.length();i++){
        delete[] arr[i];
    }
    delete[] arr;
​
    //返回最长公共子串
    return str1.substr(max_end-max_len+1,max_len);
}
​
int main()
{
    string str1 = "kkkhelaalowebyebye";
    string str2 = "kkkhelaalowebyebye111";
​
    cout<<getLCS(str1,str2)<<endl;
    cout<<getLCS1(str1,str2)<<endl;
​
    return 0;
}
​
​
​

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

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

相关文章

对比学习初认识

这篇文章我们通过SimCLR模型来对对比学习技术有一个认知。 1.什么是对比学习系统 根据上面这个图&#xff0c;来介绍下怎么做一个抽象的对比学习系统。以一个图像为例子&#xff0c;通过自动构造正例或负例&#xff0c;形成图片的两个view&#xff0c;通过encoder把它们编码&a…

第十届中医药健康文化节:御医传人龚洪海强调心血管疾病中医治疗"治未病"的重要性

在第十届中医药健康文化节上&#xff0c;备受瞩目的中医世家龚洪海医生强调了中医对心血管疾病的有效治疗&#xff0c;并提出了更为重要的概念——"治未病"。这一观念的传达不仅对预防常见病和多发病有益&#xff0c;同时在重大疑难疾病的防治中发挥着关键作用&#…

Java - OkHttp

使用方法&#xff1a; 在postman中请求接口通过&#xff0c;可复制右侧代码使用&#xff0c;可用于webservice等接口

MySQL数据库事务和存储引擎

MySQL数据库事务和存储引擎 一、mysql事务1、事务的概念2、事务的ACID特点2.1 原子性2.2 一致性2.3 隔离性2.4 持久性 3、两个事务之间的影响3.1 脏读&#xff08;读取未提交数据&#xff09;3.2 不可重复度&#xff08;前后多次读取&#xff0c;数据内容不一致&#xff09;3.3…

【Vue+Django】Training Management Platform分页功能 - 20230621

需求描述 分页显示数据&#xff0c;避免造成服务器宕机。 Django&#xff1a;根据pageNum返回数据切片 Views.py写入业务逻辑 # 数据接口&#xff1a;暴露trs_training_and_test_record数据 def api_trs_training_and_test_record(request,myDateS,myDateE,mySystem,catego…

SpringCloud Alibaba入门4之nacos注册中心管理

我们在上一章的基础上进行学习。https://blog.csdn.net/qinxun2008081/article/details/131330451 什么是注册中心?它记录了服务和服务地址的映射关系。在分布式架构中&#xff0c;服务会注册到这里&#xff0c;当服务需要调用其它服务时&#xff0c;就到这里找到服务的地址&…

Java开发必看,Spring增强性能与现代应用支持

出品 | CSDN 云计算 开发界经典话题之一&#xff0c;就是语言之争。除了每月的开发语言排行榜上几大王牌语言在榜单前列上上下下&#xff0c;在 CSDN 连续几年的年度开发者调研《中国开发者调查报告》中&#xff0c;Java 一直被评为开发者使用占比最高的语言&#xff0c;而 Spr…

银河麒麟V10 wireguard 编译

系统信息 操作系统信息&#xff1a; 我这里使用的操作系统是 银河麒麟V10&#xff0c;CPU为飞腾 ARM64 根据wireguard 的编译指南&#xff1a;https://www.wireguard.com/compilation/ 安装 编译安装内核 注意&#xff1a;5.6 以上内核不需要编译安装&#xff0c;已经集…

【数据库五】MySQL高级SQL语句

MySQL高级SQL语句 1.MySQL进阶查询1.1 select1.2 distinct1.3 where1.4 and or1.5 in1.6 between1.7 通配符1.8 like 2.MySQL数据库函数2.1 数学函数2.2 聚合函数2.3 字符串函数 3.查询函数3.1 order by3.2 group by3.3 sql语句执行顺序3.4 having3.5 别名&#xff08;字段别名…

【剑指offer专项突破版】队列篇——“C“

文章目录 前言一、滑动窗口的平均值题目分析思路分析对列代码题解代码 二、最近请求次数题目分析思路分析队列代码题解代码 三、往完全二叉树添加节点题目分析思路分析队列与接口代码题解代码 四、二叉树每层的最大值题目分析思路分析队列代码题解代码 五、二叉树最底层最左边的…

学习 WooCommerce REST API

主要学习这个技术文档即可 WooCommerce REST API 技术文档 WooCommerce 官方文档 github : woocommerce/woocommerce 以下设置以及测试代码&#xff0c;都来自 WooCommerce REST API 技术文档 设置 REST API 设置 – 固定链接 &#xff08;Settings > Permalinks.&#…

MySQL - 第4节 - MySQL数据类型

目录 1.数据类型的作用 2.数据类型分类 3.数值类型 3.1.tinyint类型 3.2.bit类型 3.3.float类型 3.4.decimal类型 4.字符串类型 4.1.char类型 4.2.varchar类型 4.3.char和varchar比较 5.时间日期类型 6.enum和set类型 6.1.enum和set类型 6.2.调查表案例 6.3.通…

二手车交易APP开发功能有哪些?

二手车交易APP开发功能有哪些&#xff1f; 1、车辆估价&#xff1a;在选购二手车时&#xff0c;了解车辆的市场价值是非常重要的。为了保证客户能够准确估计车辆的价值&#xff0c;二手车APP软件开发应该具备车辆估价功能。用户可以通过APP输入车辆的基本信息&#xff0…

离线(内网)主机创建python项目运行环境

一、创建requirements.txt文件 文件中是python项目需要的依赖和版本号 二、把依赖下载到本地 准备一个能联网的pc&#xff0c;把依赖下载到本地 pip download -d ./venv -r requirements.txt -i https://pypi.mirrors.ustc.edu.cn/simple/这个命令会把依赖下载到venv文件夹…

指数全线收跌,上证跌破3200点,仅4137只个股下跌!

如题&#xff0c;端午假期前一天&#xff0c;A股指数全线收跌&#xff0c;上证指数跌破3200点&#xff0c;仅4137只个股下跌&#xff01;就问你服不服&#xff1f; 不要急&#xff0c;不要慌&#xff0c;我们来细细分析。 过去一两周&#xff0c;上证指数以震荡为主&#xff…

嵌入式Linux学习入门

大四毕业了&#xff0c;签了一份嵌入式开发的工作&#xff0c;现在准备入门了&#xff0c;搜集一些要学习的内容。 嵌入式开发学习路线 51单片机&#xff0c;arm&#xff0c;stm32在单片机上 在单片机上编程c语言和在嵌入式系统写c语言&#xff0c;有很大不同 gcc又与我们普…

与反恐、反间谍科同级,美国国家安全部设立网络安全科

美国国家安全部&#xff08;NSD&#xff09;成立了一个新的网络部门&#xff0c;旨在能够更有力地应对高技术性的网络威胁。 这个新成立的部门&#xff0c;正式名称为国家网络安全科&#xff0c;是为了响应美国司法部 &#xff08;DoJ&#xff09; 2022 年全面网络审查中的核心…

导致JVM内存泄露的ThreadLocal详解

很常见的关于ThreadLocal的面试题的问法&#xff1a; 1.说说你对ThreadLocal的理解。 2.ThreadLocal 是什么&#xff1f;有哪 些使用场景&#xff1f;什么是线程局部变量&#xff1f; 3.ThreadLocal内存泄漏分析与解决方案。 ps:想理解好ThreadLocal&#xff0c;必须先得理…

Spring Boot命令行启动添加参数

一、Spring Boot命令行三种参数形式 通过java -jar启动springboot的jar项目时&#xff0c;可以动态传递参数来进行配置和开发&#xff0c;比如 java -jar xxx.jar --server.port8081 可以通过server.port修改项目启动的端口&#xff0c;通过命令行传递的参数具有更高的优先级…

华为OD机试 JavaScript 实现【最优策略组合下的总的系统消耗资源数】【牛客练习题】,附详细解题思路

一、题目描述 在通信系统中有一个常见的问题是对用户进行不同策略的调度&#xff0c;会得到不同系统消耗的性能。 假设由N个待串行用户&#xff0c;每个用户可以使用A/B/C三种不同的调度策略&#xff0c;不同的策略会消耗不同的系统资源。 请你根据如下规则进行用户调度&…