C++底层学习预备:模板初阶

C++ 后端开发面试知识点汇总之编译与底层(三) C++ 后端开发面试知识点汇总 阅读详情
AI摘要

本文主要介绍C++模板相关知识,在学习STL库前了解模板有助于掌握其底层原理。先阐述编程范式,包括面向对象、函数式、过程式和泛型编程;接着详细讲解函数模板,涵盖概念、原理、实例化(隐式和显式)及参数匹配原则;最后提及类模板的语法形式。

进入STL库学习之前我们要先了解有关模板的学习,以便在学习完STL库使用之后,能更深入的了解其底层工作原理

1.编程范式

编程范式指的是我们使用编程的基本风格和方法
常见的方式有以下几种:

面向对象编程(OOP)

将数据和操作数据的方法封装在类中,通过类的实例(对象)来进行交互,强调数据的封装、继承和多态性

定义一个Shape基类,包含计算面积的纯虚函数,再派生出Circle和Rectangle等类,重写计算面积的函数,体现了面向对象的继承和多态特性

函数式编程

将计算视为函数的组合和应用,强调不可变数据和纯函数,避免副作用,注重函数的输入输出关系

使用std::function和lambda表达式可以方便地进行函数式编程,如用lambda表达式定义一个简单的加法函数,不修改外部状态,只返回计算结果

过程式编程

以过程(函数)为中心,将程序分解为一系列的步骤和函数调用,数据和操作数据的函数相对独立

传统的C语言风格的编程方式,如编写一个计算阶乘的函数,通过循环和递归来实现计算过程,就是典型的过程式编程

泛型编程

定义函数、类或其他程序结构时,不指定具体的数据类型,而是使用类型参数来代表未知的数据类型

在algorithm头文件中的swap函数就是一种常见的泛式编程,他不指定任何类型就能实现交换,依靠的就是泛式编程,也是我们接下来要学习的模板

2.函数模板

在还不知道头文件前实现swap函数通常是这样的:

void Swap(int& left, int& right)
{
	 int temp = left;
	 left = right;
	 right = temp;
}
void Swap(double& left, double& right)
{
	 double temp = left;
	 left = right;
	 right = temp;
}
void Swap(char& left, char& right)
{
	 char temp = left;
	 left = right;
	 right = temp;
}

......

为了符合各个场景下实现参数互换,要对同一个函数实现不同类型的函数重载,这种方式固然可行,但是每个类型都写一遍太过于冗余了

  1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  2. 代码的可维护性比较低,一个出错可能所有的重载均出错

2.1 函数模板概念

我们知道文字的印刷是依靠活字印刷术的模板实现的,那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

这里用到的模板就是函数模板,其语法形式为:

template<typename T1, typename T2,......,typename Tn>

template就是模板的意思,是用来定义模板参数关键字,也可以使用class,切记:不能使用struct代替class,因为struct和class的默认权限不同,会导致一些混淆和潜在的问题

2.2 函数模板原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器

举个例子:

template<typename T>
void Swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

实现一个Swap交换函数

在这里插入图片描述
对两个不同类型的函数进行同一个函数的调用,调试模式下转到反汇编可以发现,两个函数式模板示例化后被调用的

这直接说明了调用的不是同一个函数

在这里插入图片描述
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。

比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,这个类型无论是内置类型还是自定义类型都可以

2.3 函数模板实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化

2.3.1 隐式实例化

让编译器根据实参推演模板参数的实际类型叫作隐式实例化

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);
	Add(d1, d2);
	return 0;
}

正常情况下的调用就是隐式实例化

🔥值得注意的是: Add函数前加const是因为这里如果像下面例子一样进行强制转化会生成临时变量,具有常性

该知识点在前面有提到过:

传送门:C++命运石之门代码抉择:C++入门(中)

2.3.2 显式实例化

在函数名后的<>中指定模板参数的实际类型叫作显式实例化

Add(a1, d1);

还是上面的例子,如果既调用int,又调用double,到底是用哪种类型编译器无法决定,就需要显式实例化

🚩用户自己来强制转化

Add(a1, (int)d1);

🚩使用显式实例化

Add<int>(a1, d1);

指定T的类型为int

这通常不是显式实例化的常用场景,举个例子:

template<class T>
T* Alloc(int n)
{
	return new T[n];
}

int main()
{
	Alloc<int>(5);
	return 0;
}

如果写成Alloc(5),编译器不知道你要分配的是int数组、double数组还是其他类型的数组,所以无法自动推导T的类型,这时候就需要显式指定模板参数,像Alloc<int>(5) 这样明确告诉编译器T是int类型

2.4 模板参数的匹配原则

🚩一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}

// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}

void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

🚩对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}

// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}

void Test()
{
	Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
	Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函
	数
}

🚩模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

这里的自动转化就是上面的实例化中的转化,也要和auto自动推导区分开,不是同一个东西

3.类模板

类模板其实和函数模板是类似的

其语法形式为:

template<class T1, class T2, ..., class Tn>

因为类不像函数那样语法上支持自动类型转化,所以类模板调用必须显式实例化

// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public:
	Vector(size_t capacity = 10)
		: _pData(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{}

	// 使用析构函数演示:在类中声明,在类外定义。
	~Vector();

	void PushBack(const T& data);
		void PopBack();
		// ...

		size_t Size() { return _size; }

	T& operator[](size_t pos)
	{
		assert(pos < _size);
		return _pData[pos];
	}

private:
	T* _pData;
	size_t _size;
	size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
	if (_pData)
		delete[] _pData;
	_size = _capacity = 0;
}

int main()
{
	// Vector类名,Vector<int>才是类型
	Vector<int> s1;
	Vector<double> s2;
	return 0;
}

我们在写模板类时尽量不要声明定义分离,原因有些复杂放在模板进阶的时候讲,如果一定分离的话要注意:

  1. 对于普通类,类名和类型一样
  2. 对于模板类,Vector类名,Vector<int>才是类型

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述

【C++】从代码示例入手(一)预备知识 每一个代码示例都有详细的解释和注释,让你能轻松理解代码的功能和运行原理,助你逐步掌握 C++的编程技巧,快速提升编程能力,为后续深入学习和开发打下坚实基础。《C++从代码示例入手》系列文章将带你开启 C++编程的探索之旅。,由浅入深地展现 C++的核心知识点, 阅读详情

相关推荐

【C++】unordered_set 容器的最全解析(什么是unordered_set?unordered_set的常用接口有那些?)

【unordered_set】是STL中的容器之一,不同于普通容器,它的查找速度极快,常用来存储各种经常被检索的数据,因为容器的底层是【哈希表】。除此之外,还可以借助其特殊的性质,解决部分难题。

weixin_45031801的博客 1万+

C++模板的底层实现

在编译器编译源代码时,如果遇到了模板的定义,编译器会将其保存在内存中,但是并不会生成对应的代码。当程序中需要使用这个模板时,编译器会根据模板参数的类型和数量,生成具体的代码,这个过程称为模板的实例化。当程序需要调用这个函数时,编译器会根据实际的参数类型,生成对应的代码。总的来说,C++ 模板的底层实现是通过编译器进行的,包括模板的实例化和代码的生成。当模板被实例化之后,编译器会根据实例化的代码生成对应的目标代码。C++ 模板的底层实现是通过编译器进行的,主要包括两个步骤:模板的实例化和代码的生成。

ZZU_LGY 4654

C++绘图 底层开发 点线面的绘制

C++计算机制图,包括点线面的绘制。地理信息系统专业课程实习。底层开发。适合初学者。

C++基础知识及相关底层汇编实现(更新中)

C++基础

最不正经的计算机专业学生 2067

浅析C++类的底层实现

如果你不了解C++类的实现机制,不知道底层如何调用构造函数,静态变量,虚函数的底层等等关于C++类的底层实现,请一定要阅读本文档,因为他会让你豁然开朗。

【eNSP 华为模拟器】单臂路由实战:从原理到配置全解析

本文详细解析了单臂路由技术,通过华为eNSP模拟器从原理到配置进行实战教学。文章阐述了单臂路由如何利用路由器单物理接口创建多个子接口,实现不同VLAN间通信,并提供了完整的操作步骤、配置命令及排错方法,帮助网络工程师掌握这一经典网络技术。

696

C/C++复习,关于底层实现

目录构造函数默认构造函数构造函数初始化列表new & deletethis生命周期和有效范围 构造函数 在C++中,有一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户显式调用(用户也不能调用),而是在创建对象时自动执行。这种特殊的成员函数就是构造函数(Constructor)。 构造函数的调用是强制性的,一旦在类中定义了构造函数,那么创建对象时就一定要调用,不调用是错误的。如果有多个重载的构造函数,那么创建对象时提供的实参必须和其中的一个构造函数匹配;反过来说,创建对象时只有一个构造

qq_41931678的博客 859

AI图像识别在临电配电箱安全检测中的应用与实践

计算机视觉与AI图像识别技术正逐步改变传统工业检测方式。通过深度学习模型如YOLOv5和ResNet,系统能自动识别设备元件并分析其状态,大幅提升检测效率和准确性。这种技术特别适用于需要严格遵循行业标准的场景,如临电配电箱的安全检测。将《施工现场临时用电安全技术规范》等条文转化为可量化的算法,AI系统能自动检查PE线连接、漏保功能等关键项目。实际应用表明,此类解决方案可使电气事故率下降90%以上,同时检测耗时缩短80%,为工地安全提供了智能化保障。

weixin_29042035的博客 326

深度探索C++对象模型笔记

一、关于对象 C 语言是程序性的,语言本身并没有支持数据和函数之间的关联性 C++ 中可能采取抽象数据类型,或者是多层次的类结构完成 C++ 的封装并没有增加多少成本,每一个成员函数虽然在class中声明,但是却不出现在每个对象中 每一个非内联的成员函数只会诞生一个函数实例 每个内联函数会在其每一个使用者身上产生一个函数实例 C++ 在布局以及存储时间上主要的额外负担是由virtual引起的 虚函数机制用以支持一个有效率的“执行期绑定” 虚基类用来实现“多次出现在继承关系中的基类,有一

hailong66666的博客 970

2026年大数据开发工程师常见面试选择题

大数据面试高频考点解析 摘要:本文汇总了30道大数据开发面试高频题目,涵盖Hadoop生态、Spark、Flink、Kafka等核心组件。重点包括:1)HDFS架构与特性(5V特征、副本机制);2)MapReduce/Spark原理(Shuffle过程、RDD抽象);3)实时计算(Kafka消费组、Flink Watermark);4)数据仓库设计(分层模型、性能优化)。特别强调数据倾斜、小文件问题等实战场景的解决方案,以及从日志、资源等多维度排查任务异常的方法。掌握这些基础原理和典型问题应对策略,是应对大

不务正业的猿 449

【同等学力】2005-数学⭐✨

有r个正方形排成一行,今用红、黄、白、蓝四种颜色给这个r个正方形染色,每个正方形只能染一种颜色,如果要求染红、黄、白色的正方形分别至少出现一个,问有多少种不同的染法?3、(4分)设G是一个有n个结点m条边的连通简单平面图,若n≥3,则m≤3n-6.4、(4分)证明:任何连通简单平面图至少有一个结点的度数不超过5

super_mochi1 305

初阶C++—— 第三节—— 动态内存管理 初识模板

我们还是先回到上一章节所说的段子: 编程世界,一切皆对象。如果没有对象的话,那就new一个出来。 这里的new就是和动态内存管理有关系了。我们今天来好好地说一说。 首先,还记得我们之前所说的C/C++的内存分布吗? 这个图其实我们已经引用第二次了。 预备知识 我们认为,C/C++ 包含内核空间、栈区、内存映射段、堆区、数据段、代码段等。 该图引自0基础C语言自学保姆教程——第十一节 自定义类型(结构体、枚举、位段、联合)与预处理指令(#define、#include等)_jxwd的博客-C

jxwd的博客 1676

Open3D 球旋转算法(BPA)三维建模【2026最新版】

球旋转算法,博客长期更新,本文最新更新时间为:2026年4月11日。

点云侠的博客 37万+

【C++】C++学习路线

分阶段的 C++ 学习路线建议

weixin_43510208的博客 2706

机器学习实战7-基于机器学习算法预测相亲成功率

大家好,我是微学AI,今天给大家介绍一下机器学习实战7-基于机器学习算法预测相亲成功率,随着社会的发展,大家都忙于事业,对自己的终身大事就耽搁了,相亲是一种传统的寻找伴侣的方式,随着时代的发展,相亲的方式也在不断地改变。在这个过程中,了解相亲双方的信息以及预测相亲是否成功变得越来越重要。本文将介绍如何使用随机森林算法对相亲成功进行预测,通过分析男女双方的房子、车子、长相、家庭条件、父母情况、生活习惯、学历、性格、兴趣等因素,来预测相亲是否成功。

微学AI的博客 3026

手把手教你学pcie--性能调优 - 中断机制优化

在PCIe系统开发中,中断机制是主机与设备之间通信的重要组成部分。然而,不当的中断设计可能导致CPU负载过高、延迟增加等问题。本文将详细介绍如何优化PCIe系统的中断机制,提升系统性能和响应速度。传统中断(INTx):通过专用引脚发送中断信号,可能引发冲突且效率较低。消息中断(MSI):通过内存写操作发送中断消息,避免冲突并提高效率。扩展消息中断(MSI-X):基于MSI改进,支持更多独立中断向量,适用于复杂场景。选择合适的中断模式对系统性能至关重要。

MHD0815的博客 281

【C++ 泛型编程 进阶篇】深入解析C++中的std::conditional_t与std::void_t:模板编程的神器

在C++的世界里,模板编程(Template Metaprogramming)是一种强大的工具,它让你能够写出更加通用、高效和可维护的代码。但是,模板编程也有它的复杂性和陷阱。这就是为什么`std::conditional_t`和`std::void_t`这两个工具如此重要。它们可以简化模板编程,让你更加专注于解决实际问题,而不是纠缠于语法和类型问题。 > "The only way to do great work is to love what you do." - Steve Jobs 正如乔布斯

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 1109

YOLOv11改进 | 注意力篇 | YOLOv11引入CA注意力机制

摘要:最近关于移动网络设计的研究已经证明了通道注意力(例如,挤压和激励注意力)对于提升模型性能的显着有效性,但它们通常忽略了位置信息,而位置信息对于生成空间选择性注意力图很重要。到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的,后期我会根据各种前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~3.2 在Extramodule里创建CA。在CA.py文件里添加给出的CA代码。

tsg6698的博客 2977

C++初阶-vector的模拟实现3

本文主要介绍了C++11中std::initializer_list的特性及其在vector模拟实现中的应用。文章首先讲解了initializer_list的基本概念、主要特性和常见用途,包括接受列表的构造函数、基于范围的for循环等。然后重点阐述了vector中initializer_list构造函数的实现原理,并通过示例代码展示了其具体应用。此外,文章还详细分析了vector的其他构造函数实现,包括迭代器区间构造、n个val值构造等,并针对int类型参数匹配问题提出了解决方案。最后给出了完整的vecto

博客是在C++/Java/Liunx/算法的学习阶段所写的博客,内容可能不是很全面 1679

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Cpp::set & map 的理解与使用(22)

刚学完二叉搜索树,我们马上来感受一下直接与它相关的两个容器吧!复杂链表的复制前K个高频单词两道很有意思的题目,大家可以尝试运用本篇文章的内容来尝试一下。

tan180°的博客 1920

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【C++】手把手教你看懂的 STL map 详解(超详细解析,小白一看就懂!!)

【map】是STL中的容器之一,不同于普通容器,它的查找速度极快,常用来存储各种经常被检索的数据,因为容器的底层是【红黑树】。除此之外,还可以借助其特殊的性质,解决部分难题。

weixin_45031801的博客 9226

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++ STL底层原理系列学习路线规划

C++ STL底层原理系列学习路线规划

深耕嵌入式领用多年, 致力于分享嵌入式领域技术! 416

【C++】set 和 map 学习及使用

set和map是STL中的容器之一,不同于普通容器,它俩的查找速度极快,常用来存储各种经常被检索的数据,因为这俩容器的底层是平衡二叉搜索树中的红黑树。除此之外,还可以借助其特殊的性质,解决部分难题set其实就是之前在二叉搜索树中key的模型set只包含实值value,或者说它的实值就是键值,键值就是实值其中的T就是set的实值(键值),参数2Compare为存储依据,默认为升序,即符合二叉搜索树升序,参数3Alloc是空间配置器,现在不必深究作为STL中的容器,set当然少不了迭代器,

Aron的博客 1203

C++逆向入门实战:从re2-cpp-is-awesome看STL程序分析

C++逆向是二进制安全分析中的核心技能,尤其当程序使用STL(标准模板库)时,反编译结果往往充斥着模板展开与复杂对象布局,让新手望而却步。理解std::string在二进制层面的存储机制、善用符号表与IDA/GDB等工具,是破解这类程序的关键。通过实战攻防世界题目re2-cpp-is-awesome,可以系统掌握如何从main函数逐行拆解STL逻辑、定位隐藏函数并提取flag。本文以工程实践视角,梳理从静态分析到动态调试的完整路径,帮助读者建立C++对象模型与汇编代码之间的映射能力,为CTF竞赛和真实恶意代

weixin_32183107的博客 633

能否跳过C语言直接学习C++?

对于想要快速应用于实际项目,或者对软件工程、游戏开发等领域有浓厚兴趣的初学者,则可以选择直接学习C++,尤其是C++11及之后的现代版本,因为它们提供了丰富的高级特性,足以独立支撑起项目开发的需求。: C语言以其接近硬件的语言特性,可以帮助初学者建立扎实的计算机系统概念,了解内存管理、指针操作等底层机制,这些在C++中同样重要,尤其是在处理效率和资源控制方面。: 另外,也可以采取折衷方案,即在学习C++的同时,适时回顾C语言的相关知识点,这样既可以利用C++的高级特性和库,也能逐步理解底层工作原理。

m0_60104735的博客 876

C++进阶-set

本文系统介绍了C++ STL中的set容器的特性与使用方法。set作为关联式容器,基于红黑树实现,具有自动去重和排序功能,增删查效率为O(logN)。文章详细讲解了set的构造函数、常用成员函数(如emplace_hint、key_comp等)以及边界查找函数(lower_bound、upper_bound等),并通过代码示例演示了其具体用法。同时对比了set与multiset的差异,指出后者允许重复元素。最后通过两个力扣编程题(查找数组交集和环形链表入口)展示了set的实际应用场景,体现了其在数据去重和快

博客是在C++/Java/Liunx/算法的学习阶段所写的博客,内容可能不是很全面 724
上一篇: 如何快速高效本地部署DeepseekR1大模型?保姆级教程 无惧隐私威胁
下一篇: C++效率掌握之STL库:string函数全解
澪贰
澪贰 优质创作者: C/C++技术领域 优质创作者: C/C++技术领域
博客等级 码龄2年 1万+粉丝 222原创
评论 64
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值