IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++入门篇(15)之模板知识进阶 -> 正文阅读

[C++知识库]C++入门篇(15)之模板知识进阶

前言

前面的章节,我们大致结束了stl基础,现在即将向模板进阶和继承多态开始出发


对于模板,博主在前面章节简答的介绍过,而此篇文章主要讲模板的一些更高级应用

模板的非类型参数

在前面的章节中,我们使用到的模板参数一直是class,但实际上,其模板参数不止有class,比如我们有此下模板:

#define N 100;
template<class T>
class Array
{
  private:
    T array[N];
};

如果我们定义一个对象—Array<int> a;,可以明显的知道,a的size等于100;

如果我们需要定义一个size等于200的Array对象呢? 很明显,我们需要修改N;

如果我们需要定义一个size等于100,一个size等于200的Array对象

呢? 很明显,我们没办法实现;

而这也就是博主需要引出来的模板的非类型参数

那么我们的非类型参数,应该怎么写呢?

template<class T,int N>
class Array
{
  private:
    T array[N];
};

定义size等于100的Array对象: Array<int,100> a;

定义size等于200的Array对象: Array<int,200> a;

注意点:

  • 该模板的N其实是常数,一旦传参以后,便不可以修改
  • N的类型只能是整型家族成员(int,long,char),不可以为浮点,字符串,自定义类型等等

模板的特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,比如

template<class T>
bool IsEqual(const T& left, const T& right)
{   
    return left == right;
}

如果是基础类型,可以得到正确结果,但如果我们的T是char*呢?

比如有char s1[]= "123",char s2[] ="123",然后分别传给left和right,那么很明显这样就会得到错误答案;因为此时left和right比较的是指针地址,并不是字符串;

所以,针对这种情况,引出了模板的特化

模板的特化:指对于具体的类型进行特殊化处理; 其中特化又分为全特化和偏特化

①模板的全特化: template后面只有<>,对于需要特化的类型,使用<>写在函数名后或者类名后

template<>     
bool Isequal<char*,char*>(char*& left,char* right) //函数模板的特化
{
    return strcmp(left,right);    //如果传入char*,就会调用该版本
}

②模板的偏特化: 即只特化某一部分类型, 其中偏特化又分为两种

第一种: template后面有<>保留但不特化的类型,对于需要特化的类型,使用<>写在函数名后或者类名后

//第一种:只特化一部分的类型
template<class T2>     
class Isequal<char*,T2> //只特化第一个类型
{
    public:
    Date(){cout<<"全特化:char* ,T2"}    

第二种: 告诉我们特化的是什么类型

//第二种,告诉我们特化的是什么类型
template<class T1,class T2>     
class Isequal<T1*,T2*> //告诉我们如果传的是指针,那么就会调用此模板
{
    public:
    Date(){cout<<"全特化:T* ,T*"}    
}

template<class T1,class T2>     
class Isequal<T1&,T2&> //告诉我们如果传的是引用,那么就会调用此模板
{
    public:
    Date(){cout<<"全特化:T& ,T&"}   
}

模板的分离编译问题

对于函数来说,它支持分离编译(即函数的声明写在.h文件中,函数的定义写在.cpp文件中);

但是对于模板来说,并不支持这样,原因是为何呢?我们先看一下程序在运行之前(编译),会经历一些什么阶段

假设目前有三个文件,分别是hp.h,hp.cpp,test.cpp,其中前两个分别是对应的分离文件

hp.h的内容有:

#pragma once
int func();

template <class T> class Array;

hp.cpp的内容有:

#pragma once
int func()
{
    return 5;
}

template <class T> 
bool is(int i)
{
	return i%2 ? true :false;    
}

test.cpp的内容为:

#include <iostream>
#include <hp.h>
using namespace std;
int main()
{
    func();
    is(2);
    return 0;
}

在前面的c语言章节,博主讲解过程序的预处理,我们知道,上面三个文件将会经理下面四个阶段:

  • 预编译: 将hp.cpptest.cpp分别变成以后缀.i结尾的文件,在这个阶段,会发生 删除注释,展开头文件,宏替换和条件编译
  • 编译: 将hp.itest.i分别变成以后缀.s结尾的文件,在这个阶段,会发生 检查语法错误,生成汇编语言
  • 汇编: 将hp.stest.s分别变成以后缀.o结尾的文件,在这个阶段,会发生 将汇编生成二进制
  • 链接: 寻找地址

前面三个阶段,我们可能很好理解,但是链接这里有点迷糊,举个例子:

test.cpp文件在变成二进制之前,按照上面步骤,它会把hp.h的内容展开到自己文件,但是这仅仅只是个声明,主函数调用两个函数时候,并不能找到函数的定义,这时候系统会给这两个函数打一个标记,代表先不管它; 等前三个阶段完成以后,链接阶段干的就是去找函数定义的位置,然后把地址发送给主函数里面的两个调用函数;

而正是这一个步骤,刚好模板会报错,为什么呢? 我们在刚学模板的时候直到,模板只有调用才会生成对于的代码;

hp.cpp中,只有模板的定义,没有调用,那么在第一个阶段,预编译时候模板定义的代码就被删除了

等到链接阶段,test.cpp去找寻模板地址时候,发现找不到定义模板的地址,就自然会报错了

因此,模板并不支持分离编译,记好哦~~


  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:43:52  更:2022-03-06 12:44:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:36:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码