首页 > 其他分享 >62. 类模板(下)

62. 类模板(下)

时间:2024-08-16 11:22:29浏览次数:11  
标签:cout SmartPointer 62 template include 模板 特化

类模板的局部特化

类模板可以定义多个类型参数

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T1, typename T2>
class Test
{
public:
    void add(T1 a, T2 b)
    {
        cout<<(a + b)<<endl;
    }
};

int main(int argc, char *argv[])
{
    Test<double, int> t;
    
    t.add(10.0001, 8);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
result:
18.0001
Press the enter key to continue ...

类模板可以被局部特化

想要为类模板指定特定的实现并希望某些类型参数仍然由模板的用户来指定

优先选择局部特化的类模板

在匹配时,优先匹配局部特化的类模板,如果同时有两个局部特化的类模板满足条件,则会让编译器进入选择困难状态,然后报错捏

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T1, typename T2>
class Test
{
public:
    void add(T1 a, T2 b)
    {
        cout<<(a + b)<<endl;
    }
};

/*
template<typename T>
class Test<T, T>
{
public:
    void add(T a, T b)
    {
        cout<<"add(T a, T b)"<<endl;
        cout<<static_cast<T>(a + b)<<endl;
    }
};
*/

template<typename T>
class Test<T, int>
{
public:
    void add(T a, int b)
    {
        cout<<"add(T a, int b)"<<endl;
        cout<<a + b<<endl;
    }
};

template<typename T1, typename T2>
class Test<T1*, T2*>
{
public:
    void add(T1* a, T2* b)
    {
        cout<<"add(T1* a, T2* b)"<<endl;
    }
};

int main(int argc, char *argv[])
{
    int i = 0;
    int j = 0;
    
    Test<double, int> t; // <T, int>
    Test<long, long> ti; // <T1, T2>
    Test<float, int> tt; // <T, int>
    Test<int*, int*> tp; // <T*, T*>

    //ps:当可以同等匹配两个局部特化时,就会出现选择困难,报错
    
    t.add(10.0001, 8);
    ti.add(2, 3);
    tt.add(4, 5);
    tp.add(&i, &j);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
result:
add(T a, int b)
18.0001
5
add(T a, int b)
9
add(T1* a, T2* b)
Press the enter key to continue ...

为什么需要特化,而不重新定义新类?

  • 特化和重新定义新类看上去没有本质区别,但是如果定义新类,那么将变成一个类模板和一个新类,使用的时候需要考虑究竟是用类模板还是用新类

  • 而特化可以统一的方式使用类模板和特化类,编译器自动优先选择特化类

(考虑友好度)

非类型模板参数

函数模板和类模板的模板参数可以是普通数值

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T, int N>
void func()
{
    T array[N] = {0};
    
    for(int i = 0; i < N; i++)
    {
        array[i] = i + 1;
        
        cout<<array[i]<<" ";
    }
    
    cout<<endl;
}

int main(int argc, char *argv[])
{
    func<int, 5>();
    func<float, 10>();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
result:
1 2 3 4 5
1 2 3 4 5 6 7 8 9 10
Press the enter key to continue ...

非类型模板参数的限制

  • 变量不能作为模板参数

  • 浮点数(现在可以)类对象不能作为模板参数

  • 全局指针不能作为模板参数

整型作为模板参数是最安全可靠的

非类型模板参数与特化

(让编译器在给我们做递归的计算)

#include <cstdlib>
#include <iostream>

using namespace std;

template<int N>//把sum变成类模板
class Sum
{
public:
//static const int s = 1;在c++中,只有static const能赋一个初值
    static const int VALUE = Sum<N - 1>::VALUE + N;//求1+...+N;
};

template< >//特化类,告诉递归何时结束,当Sum<1>的时候就不要递归了
class Sum<1>
{
public:
    static const int VALUE = 1;
};

int main(int argc, char *argv[])
{   
    //VALUE是个常量,Sum<10>是个类,通过类名访问一个static的成员常量
    cout<<Sum<10>::VALUE<<endl;//编译器编译的时候就把这件事情做完了,运行的时候没有时间开销
    cout<<Sum<100>::VALUE<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
result:
55
5050
Press the enter key to continue ...

工程问题

在实际工程中内存操作是bug的重要来源

C++将堆内存交由程序员自由使用,因此

  • 未及时释放,将产生内存泄漏

  • 重复释放同一段内存,行为未知

  • 使用越界,操作了不属于自己的内存

怎样最大限度的避开上述的使用问题?

内存越界的问题常发生于数组的使用中

解决方案:数组类

工程中,在非特殊情况下,要求开发者使用预先编写的数组类对象代替C语言中的原生数组

内存泄漏和内存多次释放常发生于指针的使用过程中

解决方案:智能指针

工程中,要求开发者使用预先编写的智能指针类对象代替C语言中的原生指针

智能指针

工程中的智能指针是一个类模板

  • 通过构造函数接管申请的堆内存

  • 通过析构函数确保堆内存被及时释放

  • 通过重载指针运算符  *和->模拟指针的行为

  • 通过重载比较运算符==和  !=  模拟指针的比较

智能指针的创建与使用

SmartPointer.h

#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_

template<typename T>
class SmartPointer
{
protected:
    T* m_pointer;
public:
    SmartPointer();
    SmartPointer(const T* pointer);//接管申请的堆内存
    ~SmartPointer();//确保堆内存被及时释放
    T* operator->();//返回一个T*类型,T*指针???
    T& operator*();//返回一个T&类型,T&地址???
};

#endif

SmartPointer.hpp

#ifndef _SMARTPOINTER_DEF_H_
#define _SMARTPOINTER_DEF_H_

#include "SmartPointer.h"

template<typename T>
SmartPointer<T>::SmartPointer()
{
    m_pointer = NULL;
}

template<typename T>
SmartPointer<T>::SmartPointer(const T* pointer)
{
    m_pointer = const_cast<T*>(pointer);//类型转换,去掉const
}

template<typename T>
SmartPointer<T>::~SmartPointer()
{
    delete m_pointer;
}

template<typename T>
T* SmartPointer<T>::operator->()
{
    return m_pointer;
}

template<typename T>
T& SmartPointer<T>::operator*()
{
    return *m_pointer;    
}    

#endif

main.cpp

#include <cstdlib>
#include <iostream>
#include "SmartPointer.hpp"

using namespace std;

class Test
{
public:
    int i;
    void print()
    {
        cout<<i<<endl;
    }
};

int main(int argc, char *argv[])
{   
    //SmartPointer<int>pi(new int(5));
    SmartPointer<int> pi = new int(5);//开始时运行构造,整个程序运行完毕运行析构
    SmartPointer<Test> pt = new Test();
    
    cout<<*pi<<endl;
    
    *pi = 10;
    
    cout<<*pi<<endl;
    
    pt->i = 20;
    pt->print();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

result

5
10
20
Press the enter key to continue ...

小结

类模板中可以有一个或多个未指定的泛指类型

可以在需要的时候特化类模板

特化可以统一的方式使用类模板和新定义的类

特化类总是被编译器优先选择使用

模板的参数可以是普通数值

数组类和智能指针可以最大限度的避免内存相关的bug

标签:cout,SmartPointer,62,template,include,模板,特化
From: https://blog.csdn.net/qq_52137184/article/details/141255170

相关文章

  • 广度优先算法 BFS总结(算法详解+模板+例题)
    一.bfs是什么广度优先搜索(Breadth-FirstSearch,简称BFS),是一种图遍历算法。它从给定的起始节点开始,逐层地向外扩展,先访问起始节点的相邻节点,然后再访问相邻节点的相邻节点,以此类推,直到遍历完所有可达节点。二.基本思路1.一直往前走,直到到达终点。2.遇到分岔路口直接分出几条......
  • 小猫爬山——dfs模板题一道
    最近做搜索里面的题目,发现还是有很多漏洞的比如下面这道小猫爬山题,还是不会做看的答案...气死我了小猫爬山时间限制: 1.000 Sec  内存限制: 128MB提交 状态题目描述Freda和rainbow饲养了N只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦......
  • ppt模板网站有哪些?带你挑选各种模板
    #周一综合征还能治好吗#?每周一早上的懊恼、拖延、抗拒……这些负面情绪,都是周日晚上熬夜屯下来的。但是问题的根源不在于周一,而在于我们对工作的态度和方法。很多人都是因为缺乏灵感和时间,而无法制作出高质量的ppt应对开会。其实,用ppt模板功能正是对抗“周一综合征”的秘密......
  • 易优Assign模板文件中定义变量-Eyoucms标签手册
    【基础用法】名称:assign功能:模板文件中定义变量,可在其他标签里使用该变量语法:{eyou:assignname='typeid'value='5'/}文件:无参数:name=''变量名value=''赋给变量名的值底层字段:无【更多示例】-------------------------------示例1------------------------------......
  • 快速符合ISO26262产品认证——动力域L2监控方案精华分享
    一、VCU应用层监控方案的ISO26262背景    “软件定义汽车”趋势下,更多汽车软件问题与消费者生命安全密切相关。而汽车行业ISO26262《道路车辆功能安全》是一个国际安全标准,对安装在量产道路车辆上的电气、电子系统的功能安全进行了约束和规定,避免对人身的伤害。  ......
  • 【算法模板】计算几何:旋转卡壳求凸包直径
    旋转卡壳算法是一种几何算法,主要用于在二维平面上求解与凸包相关的最优问题。该算法利用凸包顶点的顺序性和对称性,通过模拟两个卡壳(calipers)沿着凸包边界的旋转来寻找最优解。常见的应用包括计算凸包的直径(即最远点对之间的距离)、最小包围矩形(最小面积矩形),以及最小宽度(宽度......
  • antd模板工程
    pnpmcreatevite@latestmy-project----templatereactcdmy-projectpnpminstall-Dtailwindcsspostcssautoprefixernpxtailwindcssinit-ptailwind.config.js:/**@type{import('tailwindcss').Config}*/exportdefault{corePlugins:{......
  • ABP默认模板修改默认数据库类型并初始化数据库数据
    我这里以SQLite数据库为例,其他数据库类似。1.下载模板https://aspnetboilerplate.com/ 根据自己的需求选择版本和前端框架并填写项目名称,点击“Createmyproject!”即可下载一个ABP标准模板项目。  解压下载好的压缩包,找到目录:aspnet-core,接下来就可以用VS打开.sln......
  • c++常用模板(持续更新中)
    二分手写#include<bits/stdc++.h>usingnamespacestd;intn,m;inta[N];boolf=0;intFIND(intx){ intl=1,r=n; while(l<=r) { intmid=(l+r)/2; if(x==a[mid])returnmid; if(x<a[mid])r=mid-1; if(x>a[mid])l=mid+1; } return-1;......
  • ISO26262-MBD-静态验证在V左的布局考量
    一、ISO26262-MBD-静态验证的迷惑    模型的开发方法(Model-BasedDesign,MBD)在汽车行业嵌入式软件开发中扮演着重要的角色,功能安全ISO26262要求对我们搭建的模型进行规范检查。合规检查我们可以借助第三方工具来实现静态检查,而模型设计V左过程自动合规、如何快速合规,是我们......