首页 > 编程语言 >标准C++ -- day08

标准C++ -- day08

时间:2023-08-30 19:55:13浏览次数:38  
标签:day08 函数 -- C++ template 类型 模板 特化

一、类型信息运算符
  • typeid
    • 在C++中typeid可以获取数据的类型,需要加头文件 typeinfo

    • 通过find /usr/include -name typeinfo

    • typeid 是运算符,执行运算符函数,执行的返回值类型是type_info类类对象

    • type_info 中有个 name 的成员函数

    • type_info中还重载了 == 运算符,可以直接比较两个数据的类型是否相同

    • 可以区分父类指针或引用指向的是哪个子类,但是父子类之间必须构成多态

二、模板
1、什么是模板
  • 是一种自动生成代码的技术,这种技术能让程序员在编写代码时不需要考虑数据类型,因此也称为泛型编程技术
2、为什么要使用模板
  • C/C++/Java/C# 属于静态编程语言(编写->预处理->编译->汇编->链接->可执行文件)-强类型语言

    • 静态编程语言

      • 优点:运行速度快

      • 缺点:代码改动后重新编译、实现代码通用比较麻烦

  • C语言中的通用类型是通过 void* + 回调函数实现,实现难度大,使用比较麻烦

  • 借助定义宏的方式实现代码通用,但是宏有一定的缺点

    • 类型不检查,没有返回值,二义性
  • 借助函数重载可以实现函数代码的通用,可能会导致代码段的增多,无法解决未知类型

  • 综上所述,C++之父为了解决代码通用问题,实现了模板技术,让C++摆脱数据类型的困扰

三、函数模板
1、函数模板的定义
template<typename T1=int,typename T2=float>//加了默认形参
void func(T1 num1,T2 num2);
  • 未知类型名可以取任意名字,一般约定T
2、函数模板的原理
  • 函数模板会经历两次编译

    • 检查函数模板的语法是否有错误,如果无误,也不生成函数的二进制指令,代码段没有存储该函数模板

    • 根据调用者提供的实参类型再次编译检查函数模板代码,如果也没有错误,才会生成一份二进制指令存储在代码段中,所以,如果函数模板没有任何一次调用,则不会生成任何二进制指令,如果有不同类型的实参调用函数模板,则会生成另一份二进制指令存储在代码段中

    • 这种函数模板实例化称为 “惰性实例化”准则

3、函数模板的调用
  • C++编译器不会把函数模板当做一个函数的实体,而是当做生成函数实体的工具,当调用函数模板并提供了实际类型参数后,才会生成函数实体

  • 调用函数模板必须提供相应数量的类型参数

    • 自动:编译器会自动根据实参的类型,获取函数模板的类型

    • 手动:函数名 < type1,type2 ,type3>(实参) 会根据< >中提供的类型名去生成函数实体

4、默认形参类型
  • template<typename T1,typename T2=int,typename T3=long>
    T3 func(T1 arg1,T2 arg2)
    {
        T3 ret = arg1 + arg2;
        return ret;
    }
    
  • 函数模板的类型参数可以像普通函数的默认形参设置形参值一样去设置默认的形参类型,靠右原则一致,但是该语法只有C++11后才能支持

    • -std=gnu++0x
5、函数模板的特化
  • 模板虽好但不能直接解决所有类型的问题,有一些特殊类型与普通类型的运算规则不同,例如char*,因此需要给这些特殊类型实现一个特殊版本,这种称为函数模板的特化

  • 特化的方式:

    1. 通过 typeid( ) 分支判断类型执行特殊步骤
    if(typeid(T) == typeid(char*))
    
    1. 实现一个特化版本
  • 特化的格式

    • template<>

    • 特化类型返回值 函数名(特化类型 形参名)

  • 注意

    • 特化前,必须有一个基础版本的函数模板

    • template<> 一定要加,才说明是函数模板的特化

    • 特化函数的形参基础类型要与函数模板的形参基础类型相同,否则报错。例如函数模板中有引用,特化中也需要有

    • 编译器会优先调用函数模板中的特化版本,因此不会与基础的函数模板有冲突

    • 可以同时存在类型完全相同的普通函数、函数模板的特化、函数模板,按照普通 -->特化 -->模板的顺序调用

    • 普通函数无论是否调用都会生成二进制指令,但是函数模板的特化依然遵循 “ 惰性实例化 ”准则,不被调用时不生成二进制指令

四、类模板
使用未知类型来设计一个类类型
1、类模板定义
template<typename T1,typename T2>
class 类名
{
    T1 成员变量;
public:
    T2 func(void);
}
2、类模板的使用
  • 类模板必须实例化才能使用,与函数模板不同的是不支持自动实例化,只能显式提供类型参数手动实例

    • 类名<类型参数>对象名

    • 类名<类型参数>* 对象指针 = new 类名<类型参数>(构造函数的实参)

3、模板中的静态成员
  • 类模板中允许有静态成员,与普通类的静态成员变量一样需要在类外定义

    template<typename T>
    class 类名
    {
        static 类型名 num;
    };
    template<typename T> 
    类型名 Test<T>::num = 初始数据;
    
  • 对于每个类模板实例化出来的对象名,也是共享静态成员变量

4、递归实例化
  • 什么类型都可以是模板的类型参数,包括类模板类型
template<typename T>
class A
{
    T a;
};
template<typename T>
class B
{
    T b;
};
B<A<int>> b;    //    C++11之后才允许
B<A<int> > b;    //    C++11之前必须加空格
5、类模板的默认参数类型
  • 与函数模板的默认参数类型规则一样

    template<typename T=类型名>
    class A
    {
        T a;
    };
    
6、类模板的局部特化
  • 当类模板中的成员函数不能支持所有类型时,可以针对不同类型实现类模板中的成员函数的特化版本,称为类模板的局部特化

    • 方法1:通过 typeid 比较类型,通过分支语句执行特殊操作

    • 方法2:通过实现局部特化成员函数来处理

    template<>
    int List<const char*>::find(const char* const& data);
    
    • 注意:

      • 一般在类外实现局部特化

      • 类型名的格式除了替换的 typename 的类型发生替换,其余所有格式都需要一致,例如常属性(const)、引用等

7、类模板的全局特化
  • 为特殊类型重新特化一个类模板,称为类模板的全局特化

    template<>
    class 类名<特殊类型>
    {
        重新实现类;
    }
    
8、定义类模板和函数模板
  • class 关键字可以替换 typename

标签:day08,函数,--,C++,template,类型,模板,特化
From: https://www.cnblogs.com/bigflyny/p/17668146.html

相关文章

  • HashMap 源码分析
    HashMap简介HashMap主要用来存放键值对,它基于哈希表的Map接口实现,是常用的Java集合之一,是非线程安全的。HashMap可以存储null的key和value,但null作为键只能有一个,null作为值可以有多个JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主......
  • SpringAMQP--消息转换器
        ......
  • GDB基本操作和常见面试题
    目录GDB基本操作和常见面试题基本操作启动查看断点运行退出常见面试题GDB基本操作和常见面试题基本操作GDB是GNU开源组织发布的一个强大的Unix/Linux下的程序调试工具。作用:1、启动用户程序后,可以按照用户的要求随意运行程序2、可让被调试的程序在用户所设定的断点处停住3......
  • C++继承
    一、什么是继承当遇到问题时,先查看现有的类是否能解决一部分问题,如果有则继承该类,并在此基础上扩展以此解决问题,从而缩短解决问题的时间(代码复用)当遇到一个大而复杂的问题时,可以把大问题拆分成若干个不同的小问题,然后为每个小问题设计一个类来解决,最后通过继承的方式把这......
  • SpringAMQP--TopicExchange
             ......
  • 中芯宁波厂多名高管涉嫌挪用资金、职务侵占、商业贿赂···|百能云芯
    8月30日消息,中芯宁波通过官方微信公众号发布了“严正声明”,对于传闻进行了辟谣,并表示公司前高管黄河、王瀛以及上海蘅园高管陈宏等人涉嫌严重违法犯罪。声明指出,公司前任董事兼总经理黄河(原为美籍华人)、前财务负责人王瀛因涉嫌严重违法犯罪,已触犯刑律,目前已在刑事司法判决程序中。......
  • unp - 客户/服务器程序设计范式
    网络服务常见知识点unp中以一个echo服务为例被中断的系统调用重试accept while(true){intsockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0&&errno==EINTR){continue;}/*code*/}重试readwrite{again:while((......
  • Python 中将键值对(字典)转成数组
    将二维数组转成一维数组data=2D_shuzu().flatten()统计一维数组中重复数字的个数nnn={}.//字典foritemint:ifiteminnnn:nnn[item]+=1else:nnn[item]=1print(nnn)nnn为字典将字典(键值对)转成二位数组data=np.array(list......
  • 【五期邹昱夫】CCF-A(TIFS'23)SAFELearning: Secure Aggregation in Federated Learning
    "Zhang,Zhuosheng,etal."SAFELearning:SecureAggregationinFederatedLearningwithBackdoorDetectability."IEEETransactionsonInformationForensicsandSecurity(2023)."  本文提出了一种在联邦学习场景下可以保护隐私并防御后门攻击的聚合方法。作者认......
  • 更换固态硬盘注意事项
     更换固态硬盘前,如果现有插口“已经存在固态硬盘”,那么切记,一定不要直接更换,一定要先把“已经存在固态硬盘”拔下来,然后不要插任何硬盘,然后重启系统(或者关机再开机更好),这样是为了让主板把已经存在固态硬盘的插口重置,如果不这样操作,直接更换固态硬盘,可能会存在之前固态硬盘的缓......