【C++精华铺】8.C++模板初阶

目录

1. 泛型编程

2. 函数模板

2.1 函数模板的概念及格式

 2.2 函数模板的原理

 2.3 模板的实例化

2.4 模板参数的匹配原则

 3. 类模板

3.1 类模板格式

3.2 类模板的实例化


1. 泛型编程

        什么是泛型编程?泛型编程是避免使用某种具体类型而去使用某种通用类型来进行程序编写的方式,依次来复用某段代码而避免大规模功能相似重复冗余的代码。下面的代码如果想用泛型编程该如何实现。

int add(int a,int b)
{return a + b;
}
double add(double a, int b)
{return a + b;
}
double add(int a, double b)
{return a + b;
}

        马云有次说了这么一句话:“世界是懒人创造的,懒不是傻懒,如果你想少干,就要想出懒的方法。 要懒出风格,懒出境界。”C++必然也是有风格有境界的,所以C++中设计了模板实现了泛型编程。

2. 函数模板

2.1 函数模板的概念及格式

        模板就是一种模具,通过给这个模具中放不同的材料(类型),来获得不同材料的产品,以此来提高我们的工作效率。而函数模板就是某个函数的模具,与类型无关,在使用的时候参数化,在我们给出特定类型就会生成特定类型的版本。

        函数模板的格式:

template<typename T1, typename T2 ...typename Tn>
返回值类型 函数名(形参列表)
{
    //函数体
}

         根据这个函数的模板我们就可以实现上述add函数的模板:

template<typename L, typename R,typename RET>
RET add(L l, R r)
{return l + r;
}

注:typename是用来定义模板参数的关键字,也可以用class代替。

 2.2 函数模板的原理

        函数模板本身不是函数,而是一个模具,当我们传入实际类型的时候编译器会根据我们传入的实参类型来推演生成对应类型的函数进行调用。

 2.3 模板的实例化

        当我们将类型传入模板来生产函数的时候,称之为模板的实例化,模板的实例化分为隐式实例化和显式实例化。

        1. 隐式实例化:隐式实例化就是我们不去指定类型,让编译根据我们传入的实参判断其类型传入模板参数列表进行实例化。如下:

template<typename L, typename R>
int add(L l, R r)
{return l + r;
}
int main()
{int a = 0, b = 1;cout << add(a, b) << endl;  //根据我传入的a和b自动判断类型进行模板实例化。
}

        细心的同学发现,这里我将原来的代码中 typename RET 删掉了,原因就是模板不会对函数的返回值类型进行自动判断,而需要我们手动指定(也就是显式实例化)。

        2. 显式实例化:显式实例化就是我们手动向模板传递类型,然后由编译器进行实例化。显式实例化的格式为:

函数名<类型1,类型2,...>(实参列表);

        如: 

template<typename L, typename R, typename RET>
RET add(L l, R r)
{return l + r;
}
int main()
{int a = 0, b = 1;cout << add<int,int,int>(a, b) << endl;
}

        上述代码我们传进去的 a和b的类型与模板参数类型是匹配的,如果不匹配的话编译器会进行隐式类型转化,如果转化失败就报错。如下:
        类型转换成功:

template<typename L, typename R, typename RET>
RET add(L l, R r)
{return l + r;
}
int main()
{double a = 0.1;int b = 1;cout << add<int,int,int>(a, b) << endl;  //a:double类型隐式转换成int类型
}

输出:

        类型转化失败: 

template<typename L, typename R, typename RET>
RET add(L l, R r)
{return l + r;
}class Date
{//
};
int main()
{int a = 0, b = 1;cout << add<int,Date,int>(a, b) << endl;  //a:类型转化失败
}

输出:

E0304    没有与参数列表匹配的 函数模板 "add" 实例

2.4 模板参数的匹配原则

        一个函数的模板函数可以与非模板函数同时存在,并且在没有显式实例化且类型匹配的情况下会优先匹配非模板函数,如果是显式实例化才会调用模板,如下。

template<class T>
void swap(T& a, T& b)
{std::swap(a, b);std::cout << "我是模板 ";std::cout << a << ' ' << b << std::endl;}
void swap(int& a, int& b)
{std::swap(a, b);std::cout << "我是非模板 ";std::cout << a << ' ' << b << std::endl;}
int main()
{int a = 1, b = 2;std::cout << a << ' ' << b << std::endl;swap(a, b);   //类型匹配优先调用非模板函数swap<int>(a, b);  //调用模板实例化
}

输出:

        当我们没有去写模板的时候,函数发生类型不匹配可能会进行隐式类型转换,但是有了模板之后就不会发生隐式类型转化,而是使用模板实例化出来一个更为合适的函数。如下:
        没有模板时会发生隐式实例化:

void test(int a, int b)
{std::cout << "我不是模板" << std::endl;
}int main()
{test(2, 2.0);//2.0发生隐式类型转化成int;
}

输出:

        存在模板不会发生隐式类型转化,而是使用模板实例化出来一个更为合适的函数:

template<class T1,class T2>
void test(T1 a, T2 b)
{std::cout << "我是模板" << std::endl;
}
void test(int a, int b)
{std::cout << "我不是模板" << std::endl;
}
int main()
{test(2, 2.0);//不发生隐式类型转化而是隐式实例化模板
}

输出:

 3. 类模板

3.1 类模板格式

        和函数模板一样,类模板是类的一个模具,类模板格式如下:

template<class T1,class T2,class T3,...class Tn>
class 类模板名
{
    //类体
};

        我们普通类是可以声明和定义分离的,如果类模板要实现声明和定义分离,那么在定义的时候也要加上模板声明。如:

template<class T1, class T2>
class A
{~A();  //声明
};template<class T1,class T2> 
A<T1, T2>::~A()   //定义
{//...
}

3.2 类模板的实例化

         类模板的实例化和函数模板相同,需要在类名后加上尖括号并且指定类型。注:模板名不是类,实例化后才是一个类。

template<class T>
class Date
{//..
};
int main()
{Date<int>;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Effective C++学习笔记(7)

目录 条款41&#xff1a;了解隐式接口和编译多态条款42&#xff1a;了解typename的双重意义条款43&#xff1a;学习处理模板化基类内的名称条款44&#xff1a;将与参数无关的代码抽离templates条款45&#xff1a;运用成员函数模板接受所有兼容类型条款46&#xff1a;需要类型转…

git日常操作-案例

文章目录 查看tag对应版本tag一个版本切换到指定tag查看远程有那些分支 查看tag对应版本 要查看 Git 仓库中标签&#xff08;tag&#xff09;对应的版本&#xff0c;可以使用以下命令&#xff1a; git show <tag>将 替换为你要查看的标签名称。该命令将显示与标签对应的…

Vue3和Vue2对比学习之全局 API 应用实例

文章目录 0.前言1.参考文档2.详细说明2.1 全局 API 应用实例 非兼容2.2 一个新的全局 API&#xff1a;createAppconfig.productionTip 移除config.ignoredElements 替换为 config.isCustomElementVue.prototype 替换为 config.globalPropertiesVue.extend 移除类型推断组件继承…

【FastColoredTextBox】C# 开源文本编辑控件

主界面截图 使用Demos演示 FastColoredTextBox 是一个用于在 C# 程序中实现高亮语法着色、代码编辑和文本显示的自定义控件。它提供了许多功能&#xff0c;包括&#xff1a; 语法高亮&#xff1a;FastColoredTextBox 支持多种语言的语法高亮&#xff0c;可以根据语法规则将不同…

LinuxC编程——进程

目录 一、概念1.1 程序1.2 进程 二、特点⭐⭐⭐三、进程段四、进程分类五、进程状态六、进程状态转换图七、函数接口1. 创建子进程2. 回收进程资源3. 退出进程4. 获取进程号 八、守护进程 一、概念 进程和程序是密不可分的两组概念&#xff0c;相对比&#xff0c;便于理解。 1.…

ndk开发-交叉编译

为什么要使用交叉编译&#xff1a; 在linux系统一般使用c c编译可执行程序或者so库文件。该程序只能在当前linux系统执行&#xff0c;为了将生成文件可以再android平台运行&#xff0c;必须使用交叉编译。ndk中提供了跟多android平台交叉编译链&#xff0c;所以首先下载ndk工具…

【JUC】线程池ThreadPoolTaskExecutor与面试题解读

1、ThreadPoolTaskExecutor 创建线程池 从它的创建和使用说起&#xff0c;创建和使用的代码如下&#xff1a; 创建&#xff1a; ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize…

Yii2 advanced 框架,自定义Log日志方案

背景 近期在使用 【Yii2 advanced】框架时 在接触到 微信支付回调操作时&#xff0c;想要将微信服务器请求的参数信息记录下来 但是&#xff0c;不喜欢框架自带的日志配置方式 在此&#xff0c;推荐使用一种自定义文件目录与log记录形式的方案 希望有此需求的道友&#xff0c;能…

团团代码生成器V1.0:一键生成完整的CRUD功能(提供Gitee源码)

前言&#xff1a;在日常开发的中&#xff0c;经常会需要重复写一些基础的增删改查接口&#xff0c;虽说不难&#xff0c;但是会耗费我们一些时间&#xff0c;所以我自己开发了一套纯SpringBoot实现的代码生成器&#xff0c;可以为我们生成单条数据的增删改查&#xff0c;还可以…

ArcGIS Pro基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例全流程科研能力提升

目录 第一章 入门篇 GIS理论及ArcGIS Pro基础 第二章 基础篇 ArcGIS数据管理与转换 第三章 数据编辑与查询、拓扑检查 第四章 制图篇 地图符号与版面设计 第五章 空间分析篇 ArcGIS矢量空间分析及应用 第六章 ArcGIS栅格空间分析及应用 第七章 影像篇 遥感影像处理 第八…

Java基础知识实际应用(学生信息管理系统、猜拳小游戏、打印日历)

一、Java学生信息管理系统 这个系统包含了添加、修改、删除、查询和显示所有学生信息等功能。您可以在此基础上进行修改和完善&#xff0c;以适应您的需求。 import java.util.Scanner;public class StudentManagementSystem {private static Scanner scanner new Scanner(S…

分布式作业调度框架——ElasticJob

1、简介 ElasticJob 是面向互联网生态和海量任务的分布式调度解决方案&#xff0c;由两个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成。 它通过弹性调度、资源管控、以及作业治理的功能&#xff0c;打造一个适用于互联网场景的分布式调度解决方案&#xff0c;…