【C++之模板进阶知识】

C++学习笔记---016

  • C++之模板进阶知识
    • 1、C++模板的简单介绍
    • 2、C++模板的分类
      • 2.1、函数模板
      • 2.2、类模板
    • 3、C++模板的优缺点
      • 3.1、C++模板的主要优点包括
      • 3.2、C++模板存在的一些缺点包括
    • 4、模板参数
      • 4.1、类型参数
      • 4.2、非类型参数
      • 4.3、默认模板参数(缺省参数)
      • 4.4、多个模板参数
      • 4.4、模板参数小结
    • 5、库中的array与常用数组的区别
    • 6、模板对于按需实例化问题
    • 7、模板的特化
    • 8、模板的分离编译
    • 9、模板总结

C++之模板进阶知识

前言:
前面篇章学习了C++对于各类容器的基本使用以及常用接口的认识,接下来继续学习,C++的模板进阶等相关知识。
/知识点汇总/

1、C++模板的简单介绍

C++模板是泛型编程的基础,它允许程序员编写与类型无关的代码,从而提高了代码的重用性和灵活性。

2、C++模板的分类

C++提供了两种主要的模板类型:函数模板和类模板。

2.1、函数模板

函数模板允许程序员定义一个函数,该函数能够处理多种数据类型,而无需为每种数据类型都编写一个单独的函数。
函数模板的语法允许你定义一个函数,其中函数返回类型和参数类型可以是虚拟的类型(模板参数),然后用具体的类型来实例化这个模板。
函数模板在编译时确定具体的数据类型,从而生成针对特定类型的函数。
函数模板支持隐式实例化和显式实例化。
函数模板还可以进行重载,即定义多个具有不同模板参数的函数模板。

2.2、类模板

类模板允许程序员定义一个类,该类可以与多种数据类型一起使用,而无需为每种数据类型都编写一个单独的类。
类模板的定义语法允许你指定一个或多个类型参数,这些参数将在创建类的实例时确定。
使用类模板创建对象时,必须指明具体的数据类型。
类模板的实例化与函数模板类似,也是在编译时确定具体的数据类型。

3、C++模板的优缺点

3.1、C++模板的主要优点包括

灵活性、可重用性和可扩展性:

模板允许你编写与类型无关的代码,从而提高了代码的重用性和灵活性。

减少开发时间

通过使用模板,你可以将同一个算法应用于不同类型的数据,而无需为每个类型都编写一个单独的版本。

模拟多态的效率

模板模拟多态的效率通常比使用C++类继承实现多态要高,因为它避免了虚函数和继承的开销。

3.2、C++模板存在的一些缺点包括

易读性较差

模板代码相对于普通代码来说可能更难阅读和理解。

调试困难

由于模板在编译时生成具体的代码,因此调试模板代码可能会更加困难。

编译时间较长

当工程较大时,包含大量基于模板算法的实现可能会导致编译时间增加。

4、模板参数

在C++模板中,模板参数是用于指定模板类型或值的参数。模板参数可以是类型参数(type parameters)或非类型参数(non-type parameters),它们在模板定义中被声明,并在模板实例化时提供具体的值或类型。

4.1、类型参数

类型参数用于指定模板中类型的占位符。在模板实例化时,这些占位符将被具体的类型所替代。类型参数通常在尖括号(<

)中声明,并且可以使用任何有效的C++类型。

template <typename T> // 声明一个类型参数T  
class MyClass {  
public:  
    T value;  
    MyClass(T v) : value(v) {}  
    void printValue() {  
        std::cout << value << std::endl;  
    }  
};  
  
// 实例化模板类MyClass,T被int替代  
MyClass<int> myInt(42);  
myInt.printValue(); // 输出:42  
  
// 实例化模板类MyClass,T被std::string替代  
MyClass<std::string> myString("Hello, World!");  
myString.printValue(); // 输出:Hello, World!

4.2、非类型参数

非类型参数允许你在模板中指定非类型的值,如整数、枚举值或指针等。非类型参数在模板实例化时必须是一个常量表达式,并且它们的类型必须允许在编译时计算其值。

template <int N> // 声明一个非类型参数N  
class Array {  
public:  
    int data[N];  
    // ...其他成员函数...  
};  
  
// 实例化模板类Array,N被5替代  
Array<5> myArray; // 创建一个包含5个int的数组  
  
// 注意:非类型参数不能是引用类型或浮点数类型  
// 因为它们不能在编译时计算其值或大小

4.3、默认模板参数(缺省参数)

你可以为模板参数提供默认值,以便在模板实例化时省略这些参数。这可以增加模板的灵活性,使得模板的使用更加简洁。

template <typename T = int> // 声明一个类型参数T,并提供默认值为int  
class DefaultClass {  
public:  
    T value;  
    // ...其他成员函数...  
};  
  
// 实例化模板类DefaultClass,省略类型参数T,使用默认值int  
DefaultClass<> defaultInt; // T被int替代  
  
// 实例化模板类DefaultClass,指定类型参数T为double  
DefaultClass<double> defaultDouble; // T被double替代

4.4、多个模板参数

模板可以拥有多个类型参数和非类型参数,这些参数之间用逗号分隔。

template <typename T, typename U, int N> // 声明两个类型参数T和U,以及一个非类型参数N  
class PairArray {  
public:  
    T first[N];  
    U second[N];  
    // ...其他成员函数...  
};  
  
// 实例化模板类PairArray,T被int替代,U被double替代,N被5替代  
PairArray<int, double, 5> myPairArray;

4.4、模板参数小结

模板参数是C++模板编程的核心,它们使得模板能够处理不同类型和值的代码,从而提高了代码的重用性和灵活性。
注意
1.浮点数、类对象以及字符串是不允许作为非类型模板参数的
2.非类型的模板参数必须在编译期间就能确认结果。

5、库中的array与常用数组的区别

#include <iostream>
#include <array>
#include <vector>
using namespace std;

int main()
{
	std::array<int, 10> a1;
	int a2[10];
	//库中封装的array的区别在于,优化了越界检查

	//越界读,检查不出来
	a2[10];
	cout << a2[10] << endl;
	//越界写,属于抽查
	a2[10] = 1;
	cout << a2[10] << endl;
	a2[15] = 1;//没被抽查到越界
	cout << a2[15] << endl;

	//对于库的越界检查,优化了这个问题
	//越界读,断言
	a1[10];
	cout << a1[10] << endl;
	//越界写,断言
	a1[10] = 1;
	cout << a1[10] << endl;

	//但是实际上,在具体的应用层面上,实际上这个优化并没有多大用处,完全可以使用vector解决,并且还能顺便初始化
	vector<int> v(10, 0);
	cout << v[9] << endl;
	cout << v[10] << endl;//断言检查

	//另外,还可能存在栈溢出的问题,因为静态数组是在栈区上开辟空间的。
	array<int, 1000000> a3;
	cout << sizeof(a3) << endl;
	//但是交给vector就不会溢出
	vector<int> v2(1000000, 0);
	cout << sizeof(v2) << endl;
	return 0;
}

6、模板对于按需实例化问题

在一些场景并不会报错,因为没有调用operator[],所以operator[]有调用参数不匹配,没有检查出来的情况。
一旦调用就会实例化,才会细致检查语法的错误,参数错误等。

//按需实例化:
//调用哪个成员函数编译器就实例化哪个成员函数
T& operator[](size_t index)
{
	return _array[index];
}
const T& operator[](size_t index) const
{
	assert(index < N);
	size(1);//按需实例化问题
	return _array[index];
}

7、模板的特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果;需要特殊处理,比如专门实现进行小于比较的模板。

#include <iostream>
using namespace std;

template<class T>
bool Less(T left, T right)
{
	return left < right;
}

//类模板的特化 --- 单独写特化是不行的
template<>
bool Less<int*>(int* left, int* right)
{
	return left < right;
}

//半特化
template<class T1>
bool Less(T1* left, int* right)
{
	return left < right;  
}


int main()
{
	int a = 1;
	int b = 2;
	cout << Less(a, b) << endl;
	return 0;
}

8、模板的分离编译

什么是分离编译?

一个程序由若干个源文件共同实现,而每一个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行的过程称为分离编译模式。

#include <iostream>
#include "array.h"
using namespace std;

int main()
{
	/*
	bit::array<int> a;
	cout << a.size() << endl;
	//编译size和func时都只有声明,编译时,检查一下函数名和参数匹配就暂且通过,
	//而它的定义在其他.cpp文件中,链接时再去其他文件中找函数的地址。
	//当链接时,找不到函数地址就报链接错误
	bit::Func();
	//func和size现在都有声明和定义了
	//为什么链接时,func能找到,而size还是找不到呢?
	//本质就是调用size时,编译器不知道该怎么实例化。size有两个模板参数,且拿不到地址

	//解决1:显示实例化(比较局限)
	bit::array<double> a2;
	cout << a2.size() << endl;
	*/

	//解决2:利用模板的特性,声明和定义放入同一个.h文件中
	bit2::array<int> a3;
	cout << a3.size() << endl;
	bit2::array<double> a4;
	cout << a4.size() << endl;

	//为什么模板的定义放到.h就不会报错呢?
	//因为.h预处理展开后,实例化模板时,既有声明也有定义,直接就实例化,
	//所以编译时,有函数的定义,直接就有地址,不需要等链接再去找地址了。
	return 0;
}

9、模板总结

模板的优点:
1.模板复用了代码,节省了资源,更快的迭代开发,C++的标准模板库(STL)因此产生。
2.模板增强了代码的灵活性。
模板的缺点:
1.模板容易导致代码膨胀的问题,也会导致编译的时间长的问题。
2.出现模板编译出错时,错误信息凌乱,不易调试和定位解决错误。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode297_二叉树的序列化与反序列化

1.leetcode原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 2.题目描述 序列化是将一个数据结构或者对象转换为连续的比特位的操作&#xff0c;进而可以将转换后的数据存储在一个文件或者内存中&#xff0c;同时也可以通过网络传输到另一个计算机环境&#xf…

redis故障中出现的缓存击穿、缓存穿透、缓存雪崩?

一、背景&#xff1a; 在维护redis服务过程中&#xff0c;经常遇见一些redis的名词&#xff0c;例如缓存击穿、缓存穿透、缓存雪崩等&#xff0c;但是不是很理解这些&#xff0c;如下就来解析一下缓存击穿、缓存穿透、缓存雪崩名词。 二、缓存穿透问题&#xff1a; 常见的缓存使…

RTMP 直播推流 Demo(一)—— 项目配置与视频预览

音视频编解码系列目录&#xff1a; Android 音视频基础知识 Android 音视频播放器 Demo&#xff08;一&#xff09;—— 视频解码与渲染 Android 音视频播放器 Demo&#xff08;二&#xff09;—— 音频解码与音视频同步 RTMP 直播推流 Demo&#xff08;一&#xff09;—— 项目…

使用JNI机制加载本地方法的小案例

JNI 最近在学习Android&#xff0c;其中需要使用到c的库&#xff0c;这个时候就要使用到JNI机制了&#xff0c;简单来说&#xff0c;就是可以通过这个机制&#xff0c;让java代码可以调用本地c语言编写的代码&#xff0c;将c语言编写的代码打包成动态库&#xff0c;然后&#…

Java面试重点之反射机制

一、 反射是什么&#xff1f; 允许程序在运行时查询和操作对象的类型信息。通过反射&#xff0c;程序能够在运行时获取对象的类定义信息&#xff0c;如类的名称、方法、字段、注解等&#xff0c;并且可以动态地调用对象的方法或访问其字段&#xff0c;而无需在编译时具体知道对…

CarEye 智能叉车管理系统

CarEye 团队在智能车辆管理平台基础上&#xff0c;专门针对叉车管理特殊性开发了叉车管理系统。以下是叉车管理系统的一些主要介绍&#xff1a;

跟TED演讲学英文:Innovating to zero! by Bill Gates

Innovating to zero! Link: https://www.ted.com/talks/bill_gates_innovating_to_zero Speaker: Bill Gates Date: February 2010 文章目录 Innovating to zero!IntroductionVocabularyTranscriptQ&A with Chris AndersonSummary后记 Introduction At TED2010, Bill Ga…

深度学习突破:LLaMA-MoE模型的高效训练策略

在人工智能领域&#xff0c;大模型&#xff08;LLM&#xff09;的崛起带来了前所未有的进步&#xff0c;但随之而来的是巨大的计算资源需求。为了解决这一问题&#xff0c;Mixture-of-Expert&#xff08;MoE&#xff09;模型架构应运而生&#xff0c;而LLaMA-MoE正是这一架构下…

环形链表题

1.环形链表1 看题&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 思路1&#xff1a;哈希表 遍历所有节点&#xff0c;每次遍历一个节点时&#xff0c;判断该节点是否被访问过。 可以使用哈希表来存储所有已经访问过的节点。每次到达一个节点&#xff0c;如果该节点已…

windows查看nginx是否启动

windows查看nginx是否启动 1.通过命令提示符: 打开命令提示符&#xff08;CMD&#xff09;。您可以通过按下WinR键&#xff0c;然后输入“cmd”并按下Enter键来打开命令提示符窗口。 输入命令 tasklist /fi “imagename eq nginx.exe”。如果命令执行后能看到nginx进程&#x…

【DeepL】菜鸟教程:如何申请DeepL免费API并使用Python的DeepL

前言 在这篇技术博文中,我们将介绍如何利用DeepL的强大功能,通过其免费API在Python项目中实现高质量的文本翻译。我们将从基础开始,解释DeepL是什么,它的用途,如何申请免费API,以及如何在Python中使用DeepL库。 什么是DeepL? DeepL是一个基于人工智能的翻译服务,它以…

RocketMQ MQTT 快速搭建验证

来自业务的需求&#xff0c;需要快速搭建一套支持 MQTT 协议的消息系统。 前期准备&#xff1a; 官方地址&#xff1a;https://github.com/apache/rocketmq-mqtt RocketMQ从4.9.3 版本开始才支持该功能&#xff0c;所以需要先检查 RocketMQ 的版本是否满足。 RocketMQ 部署参…

Java同时使用@RequestBody和@RequestParam传参在postman中执行请求报错:Unsupported Media Type

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Laravel5.4 反序列化

文章目录 0x01 环境搭建0x02 POP 链0x03 exp0x04 总结 前言&#xff1a;CC 链复现的头晕&#xff0c;还是从简单的 Laravel 开始吧。 laravel 版本&#xff1a;5.4 0x01 环境搭建 laravel安装包下载地址 安装后配置验证页面。在 /routes/web.php 文件中添加一条路由&#xf…

神之浩劫2下载教程 MOBA新游神之浩劫2在哪下载/怎么下载

《神之浩劫2Smite 2》重新定义了MOBA游戏的征服模式&#xff0c;为玩家带来更多的互动和进展。最近的开发者深度挖掘展示了游戏地图的全新设计&#xff0c;既简化了基本操作&#xff0c;又丰富了游戏选择。游戏中的敌人也有了新的进展方式。例如&#xff0c;击败火巨人和金之怒…

【深度学习基础(1)】什么是深度学习,深度学习与机器学习的区别、深度学习基本原理,深度学习的进展和未来

文章目录 一. 深度学习概念二. 深度学习与机器学习的区别三. 理解深度学习的工作原理1. 每层的转换进行权重参数化2. 怎么衡量神经网络的质量3. 怎么减小损失值 四. 深度学习已取得的进展五. 人工智能的未来 - 不要太过焦虑跟不上 一. 深度学习概念 先放一张图来理解下人工智能…

powershell 注册全局热键——提升效率小工具

powershell 注册全局热键 01 前言 在处理一些重复工作问题的时候&#xff0c;想搞一个小工具&#xff0c;配合全局快捷键来提高效率。因为是Windows系统&#xff0c;想到C#&#xff0c;但是又不想用VS开发&#xff0c;因为那样不够灵活&#xff0c;没办法随时修改随时用&…

Spring ai 快速入门及使用,构建你自己的ai

第一步&#xff1a;创建springboot项目 jdk必须是17及以上 1.8用不了 第二步 选择web和ai的依赖 选择openai 第三步 需要配置openai key 配置 分享个免费或的apikey的地方New API 会免费赠送1刀的token spring.application.namespringAI spring.ai.openai.base-urlhttps://ap…

推荐一个好用的命令行工具ShellGPT

ShellGPT 配置安装常用功能聊天写命令并执行 高级功能函数调用角色管理 总结 这两天突然想到&#xff0c;现有的很多工具都在被大模型重构&#xff0c;比如诞生了像perplexity.ai 这种新交互形式的搜索引擎&#xff0c;就连wps也推出了AI服务&#xff0c;甚至都可以直接生成ppt…

JavaScript转换和校验数字

本节我们使用的案例还是继续之前的银行家应用程序&#xff0c;只不过我们呢增加了两个账号&#xff0c;代码如下&#xff1a; const account1 {owner: Jonas Schmedtmann,movements: [200, 455.23, -306.5, 25000, -642.21, -133.9, 79.97, 1300],interestRate: 1.2, // %pin…
最新文章