C++ 中 struct 与 class 的核心差异与应用场景
导言在 C++ 编程中,struct与class是定义复合数据类型的核心语法元素,二者既共享大部分 OOP(面向对象编程)特性,又因设计初衷不同存在关键差异。 一、语法定义与核心共性struct源于 C 语言的结构化数据设计,class则是 C++ 为支持 OOP 引入的特性。在 C++ 标准(ISO/IEC 14882)中,二者功能上高度重合,仅在默认行为上存在差异。 1.1 核心共性 成员定义能力:均可包含数据成员(如int x)和成员函数(如void print()),支持静态成员(static)和友元(friend)。 OOP 特性支持:均支持构造函数、析构函数、拷贝 / 移动语义、继承、多态(虚函数)。 内存布局规则:数据成员的对齐(alignment)、填充(padding)逻辑完全一致,由编译器根据平台(如 32 位 / 64 位)和类型大小决定。 模板与容器适配:均可作为 STL 容器(如std::vector)的元素类型(需满足容器要求,如可拷贝性)。 1.2 共性示例代码1234567891011121314151617...
C++ 类间关系与功能复用
导言在面向对象编程的世界里,类与类之间的关系设计和功能复用机制是构建高质量软件的基石。理解这些概念不仅有助于写出结构清晰的代码,更能提升系统的可维护性和扩展性。本文将结合实例,深入探讨 C++ 中类间的五大关系(继承、组合、聚合、关联、依赖),并分享对功能复用的理解与实践经验。 一、对类间关系的本质理解类间关系本质上反映了现实世界中事物之间的联系,是对客观世界的抽象。在面向对象设计中,我们通过类间关系来建模这些联系,使软件系统更贴近现实逻辑。 类间关系并非孤立存在,它们之间存在着从强耦合到弱耦合的渐变过程:继承 > 组合 > 聚合 > 关联 > 依赖。这种耦合度的差异,决定了它们在不同场景下的适用性。 让我们以基础类 A 为核心,通过具体代码来理解这些关系: 123456789class A{public: friend class E; void func() { cout << "hello,world" << endl; }}; ...
C++ 使用 bind / mem_fn 了解函数对象与可调用实体
一、核心概念辨析在开始代码实现前,需先明确三个核心概念的区别: 概念 定义 典型示例 可调用实体 (Callable Entity) 所有可以通过()语法调用的对象或表达式的统称 函数指针、lambda 表达式、仿函数、bind返回对象 函数对象 (Function Object) 具有operator()成员函数的类实例(仿函数) 自定义struct Add { int operator()(int a, int b); } 可调用对象 (Callable Object) 除函数指针外的可调用实体,强调 "对象" 属性 lambda 表达式、std::bind返回值、std::mem_fn返回值 二、完整代码实现以下代码基于 C++11 标准实现,包含自由函数绑定、成员函数绑定、参数占位符使用、带状态函数对象等典型场景: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585...
图形计算程序
引言在传统的 C++ 面向对象设计中,我们通常使用虚函数实现多态。本文将展示如何使用std::function替代虚函数,并结合移动语义,构建一个更灵活高效的图形计算程序。这种方式不仅能保持多态性,还能提升性能并增加代码灵活性。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631...
C++ 文件读取再整理
一、文件读取核心概念与基础流程1.1 文件操作的三要素文件读取本质是 "数据在外部存储与内存间的传输过程",需关注三个核心要素: 流对象:C++ 标准库通过std::ifstream(输入文件流)提供文件读取接口,是连接程序与外部文件的桥梁 流状态:通过good()/eof()/fail()/bad()四个状态标志判断操作有效性 数据缓冲区:操作系统与标准库均会维护缓冲区,减少磁盘 IO 次数(默认缓冲区大小通常为 4KB 或 8KB) 1.2 基础文件读取流程(标准范式)所有文件读取操作都遵循 "打开 - 读取 - 关闭" 的核心流程,标准实现代码如下: 123456789101112131415161718192021222324252627282930313233343536373839#include <fstream>#include <iostream>#include <string>int main() { // 1. 创建流对象并打...
C++ 中 std::bind 与 std::function
一、std::function —— 可调用对象的 "万能容器"1.1 概念解析:什么是 std::function?std::function 是 C++11 标准库 头文件中引入的通用可调用对象封装器,其核心作用是将各种不同类型的可调用实体(函数指针、成员函数指针、lambda 表达式、函数对象)统一到一个类型安全的容器中。 可以将其类比为 "函数的通用接口转换器"—— 无论原始可调用对象的类型如何,只要签名(返回值类型 + 参数类型列表)匹配,就能被 std::function 封装并统一调用。 1.2 实现原理:类型擦除(Type Erasure)std::function 本质是通过类型擦除技术实现的多态封装,核心流程如下: 定义一个抽象基类(如 function_base),包含纯虚函数 operator()(对应目标签名)和析构函数; 为每个具体的可调用对象类型,实现一个模板派生类(如 function_impl),继承自 function_base,并在 operator() 中调用具体对象; std::functi...
C++核心语法整理
C++核心语法整理C与C++类与对象C++输入输出流友元与运算符重载关联式容器继承多态模板移动语义与资源管理C与C++ C++程序介绍 g++编译器安装 sudo apt install g++ 源文件名称 .cc .cpp C++程序模板设置 /home/st/.vim/plugged/prepare-code/snippet hello world程序分析 #include C++标准库中头文件 没有.h cin 标准输入流 默认输入设备 从键盘接收数据 cout 标准输出流 默认输出设备 屏幕 int main(int argc , char *argv[]){} 返回值为int argc 命令行参数的个数 argv 具体的命令行参数 vim中启动鼠标 编辑.vimrc文件 子主题 命名空间 命名空间是什么, 有什么作用? C++中的一种避免名字冲突的机制 主要作用区分同名实体 实体 变量、常量、函数、结构体、类、对象...
func(int) & func(int x)
一、核心区别:参数名的「存在意义」先明确最本质差异:**func(int){}**省略参数名,**func(int x){}**指定参数名x。这一区别在函数「声明」和「定义」场景中影响截然不同,且仅在 C/C++ 等少数语言中合法(Python、Java 等需强制指定参数名)。 二、分场景深度解析1. 函数声明阶段:几乎无差异在头文件或函数原型声明中,两者作用完全一致 ——仅告知编译器「函数接收一个 int 类型参数」,参数名不影响函数签名。 示例: 123// 以下两种声明等效,编译器均识别为「接收int、返回void」的函数void func(int); // 省略参数名(常用)void func(int x); // 带参数名(可选,仅作注释提示) 正如中关村在线问答指出的:声明只需说明参数类型,参数名「没什么用」。编译器处理时,会忽略声明中的参数名,仅记录函数名和参数类型序列。 2. 函数定义阶段:可用性天差地别函数定义(实现)时,参数名的有无直接决定「能否在函数体内使用该参数」: func(int x){}:可正常操作参数 x是参数的...
STL标准模板库内容整理
STL标准模板库(重点):C++工具(类模板与函数模板) STL标准模板库 本质上就是数据结构和算法 C语言标准库未直接提供 C++标准库直接提供 定义:高效C程序库,含基本数据结构和算法,属C标准库,采用泛型编程 泛型编程:抽象数据类型,用泛型代替具体类型,编写通用代码 六大组件 容器(重要):存储数据(数据结构) 序列式容器:vector、list、deque等 关联式容器:set、map等 无序关联式容器:unordered_set、unordered_map等 迭代器:访问容器元素,泛型指针(例:vector::iterator) 算法:操作容器元素的普通函数(例:std::sort) 适配器:适配作用 容器适配器:stack、queue、priority_queue 迭代器适配器 函数适配器:bind、bind1st、bind2nd、function等 函数对象:实现定制化操作 空间配置器:管理内存(使用、原理、源码) 六大组件 容器 作用:存放数据 1、序列式容器 模型理解 array 静态数组,大小固定的数...
C++ 实现高效单词转换工具
一、需求与设计分析1.1 核心需求根据 C++ Primer 11.3.6 练习要求,工具需满足以下功能: 规则加载:从map.txt读取替换规则(每行格式:待替换单词 替换后的短语) 文本处理:读取file.txt中的待转换文本,将匹配规则的单词替换为对应短语 结果输出:将替换后的文本写入output.txt 灵活性:支持通过命令行参数自定义规则文件、输入文件和输出文件路径 鲁棒性:处理文件打开失败、格式错误等异常情况 1.2 示例输入输出 规则文件(map.txt):定义替换映射 12345678brb be right backk okay?y whyr areu youpic picturethk thanks!l8r later 待转换文本(file.txt):包含缩写词的原始文本 123where r uy dont u send me a pick thk l8r 预期输出(output.txt):替换后的标准文本 123where are youwhy dont you send me a pictureokay? thanks! later ...
《STL 源码剖析》读书笔记
导言作为具备一定工程实践经验的中级软件工程师,在日常软件开发工作流中,C++ 标准模板库(Standard Template Library,STL)的容器与算法体系已成为不可或缺的编程工具。vector 的动态内存管理机制、map 的有序键值对存储特性,以及 sort 算法的高效执行范式,这些看似常规的编程操作,实则蕴含着深邃的计算机科学设计思想。通过研读侯捷所著《STL 源码剖析》,得以系统性解构 STL 的底层实现逻辑,深刻体会到 "知其然更知其所以然" 在软件工程领域的重要价值。 一、数据结构:从应用层到实现层的认知跃迁在数据结构层面,STL 核心容器的底层实现机制在书中得到细致解析。以 vector 容器为例,其动态数组特性不仅体现在可扩展的存储容量上,更在于其内存管理策略的精妙设计。当容器容量不足时,vector 采用指数级扩容策略(通常为原容量的 2 倍或 1.5 倍,依具体实现而定),通过重新分配内存空间、元素迁移及旧内存释放的流程,在空间复杂度与时间复杂度之间实现了高效平衡。这种 "以空间换时间" 的策略,有效规避了频繁内...
迭代器与迭代适配器
引言:迭代器的核心价值在 C++ 标准模板库 (STL) 中,迭代器扮演着 "胶水" 的角色,它连接了容器与算法,使算法能够独立于具体容器类型工作。这种抽象机制带来了极大的灵活性 —— 同一个排序算法可以作用于向量 (vector)、链表 (list) 或数组 (array),只需它们提供兼容的迭代器。 迭代适配器则是在基础迭代器之上的增强,通过包装现有迭代器,提供反向遍历、插入操作等特殊行为,进一步扩展了迭代器的能力。本文将系统解析迭代器的分类、实现原理及迭代适配器的应用场景。 一、迭代器基础:概念与分类1.1 迭代器的本质迭代器本质上是一种泛化的指针,它重载了*、->、++等运算符,使开发者能够以统一的方式访问容器中的元素,而不必关心容器的内部实现细节。 1234567891011121314151617181920212223#include <vector>#include <list>#include <iostream>// 通用打印函数,适用于任何提供输入迭代器的容器template<typenam...
函数对象
一、函数对象的本质函数对象(也称为仿函数,Functor)是*重载了函数调用运算符***operator()**的类或结构体的实例。这种特殊的设计使它能够像普通函数一样被调用,同时又具备对象的所有特性。 12345678910111213141516// 一个简单的函数对象类struct Add { // 重载函数调用运算符 int operator()(int a, int b) const { return a + b; }};// 使用方式int main() { Add add; int result = add(3, 5); // 像函数一样调用对象 // 也可以直接使用临时对象 int result2 = Add()(10, 20); return 0;} 从本质上讲,函数对象是一个带行为的对象,而普通函数是一段可执行代码。这种本质差异决定了它们在功能和适用场景上的不同。 二、函数对象与普通函数的核心区别2.1 状态管理能力这是两者最根本的区别...
C++ Lambda 表达式
导言在现代 C++ 开发中,lambda 表达式(匿名函数)已经成为编写简洁高效代码的重要工具。尤其在配合 STL 算法(如for_each)时,lambda 表达式能够消除编写命名函数或函数对象的额外开销,使代码更加紧凑直观。 一、Lambda 表达式的基本语法lambda 表达式的完整语法结构如下: 123[capture](parameters) mutable noexcept -> return_type { // 函数体} 各组成部分的含义: [capture]:捕获列表,定义 lambda 表达式可以访问的外部变量 (parameters):参数列表,与普通函数的参数列表类似 mutable:可选修饰符,允许修改按值捕获的变量 noexcept:可选修饰符,指定函数不会抛出异常 -> return_type:返回类型,当函数体只有 return 语句时可省略 {}:函数体,包含具体的执行逻辑 1.1 最简单的 Lambda 表达式最简化的 lambda 表达式可以省略参数列表、返回类型和修饰符,仅保留捕...
unordered_map存放自定义类具体实现
一、引言上一篇文章介绍了unordered_map存放自定义类型的六种方法的理论框架,本文将通过完整可运行的代码示例,详细展示每种方法的具体实现细节。这六种方法是通过 2 种哈希实现方式与 3 种相等性比较方式组合而成,每种组合都有其独特的实现要点。 二、基础准备首先定义基础的Point类和测试函数,作为六种方法的共同基础: 12345678910111213141516171819202122232425262728293031323334353637383940#include <iostream>#include <unordered_map>#include <string>#include <functional>// 自定义点类型class Point {private: int x; int y;public: Point(int x_ = 0, int y_ = 0) : x(x_), y(y_) {} int getX() const { re...
unordered_map 存放自定义类型的六种方法
引言std::unordered_map是 C++ 标准库中提供的无序关联容器,与std::map不同,它通过哈希表实现,因此需要两个关键组件:哈希函数(用于计算键的哈希值)和相等性比较函数(用于判断两个键是否相等)。当使用自定义类型作为unordered_map的键时,我们需要显式提供这两种组件。 一、核心概念std::unordered_map的模板定义如下: 1234567template< class Key, class T, class Hash = std::hash<Key>, // 哈希函数类型 class KeyEqual = std::equal_to<Key>, // 相等性比较类型 class Allocator = std::allocator<std::pair<const Key, T>>> class unordered_map; Hash类型必须满足Hash概念:Hash对象的operator()接受const Key&参数,返回s...
C++ 容器的选择
一、关联式容器与无序关联容器的核心区别关联式容器(如set、map、multiset、multimap)和无序关联式容器(如unordered_set、unordered_map、unordered_multiset、unordered_multimap)是 C++ STL 中两种不同的数据结构,核心区别在于底层实现和特性: 关联式容器:基于红黑树(一种自平衡二叉搜索树)实现,元素按照键(key)的有序性存储,默认通过less比较键的大小。 无序关联式容器:基于哈希表实现,元素存储顺序与键的大小无关,依赖哈希函数计算存储位置,通过键的哈希值快速访问元素。 二、如何选择:关联式容器 vs 无序关联式容器选择需根据具体场景的需求,主要从以下维度判断: 2.1 有序性需求 需要元素有序:优先选择关联式容器。例如: 需遍历元素时按键的大小排序(如set遍历默认升序); 需频繁执行范围查询(如map::lower_bound、map::upper_bound获取键在[a, b]之间的元素)。 无需有序性:优先选择无序关联式容器,其插入、查找、删除的平均效率更高。 2.2 ...
STL 容器的成员函数与相关函数
引言C++ 标准模板库(STL)提供了一系列功能丰富的容器,这些容器不仅封装了数据结构,还提供了大量成员函数用于操作数据。此外,STL 还包含许多与容器配合使用的非成员函数,它们扩展了容器的功能,使操作更加灵活。 一、通用成员函数几乎所有 STL 容器都提供了一组基础的通用成员函数,用于获取容器信息、修改容器状态等。 1.1 基本信息函数12345678910111213141516171819202122#include <iostream>#include <vector>#include <list>int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; std::list<std::string> lst = {"apple", "banana", "cherry"}; // 容器大小相关 std::cout <<...
map 存放 pair<Point,string> 的三种解决方案
引言在 C++ 中使用std::map存储自定义类型作为键时,需要确保该类型能够被正确比较大小,因为std::map是一个有序关联容器,其内部通过比较操作来组织元素。本文将介绍三种方法来解决map中存放pair<Point, string>元素的问题,其中Point是一个自定义点类型。 核心概念std::map要求其键类型必须支持比较操作(默认使用<运算符)。对于自定义类型Point,我们需要通过以下三种方式之一提供比较能力: 为Point类重载<运算符 定义一个比较结构体(仿函数) 为Point准备std::less的特化模板 代码示例首先定义基础的Point类: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <math.h>#include <iostream>#include <set>using std::cout;using std::endl;...
迭代器与指针
引言在 C++ 中,迭代器 (iterator) 和指针 (pointer) 是两个密切相关但又有所区别的概念。它们都可以用来访问内存中的数据,都支持类似的操作符 (如*和->),但应用场景和功能范围却有显著差异。本文将深入解析迭代器与指针的关系、区别及各自的应用场景。 核心概念指针的本质指针是 C++ 从 C 语言继承而来的概念,是一个变量,其值为另一个变量的内存地址。指针直接指向内存中的某个位置,可以是: 普通变量的地址 数组元素的地址 动态分配内存的地址 函数的地址 迭代器的本质迭代器是 C++ 标准库提供的一种抽象,它模拟了指针的行为,为各种容器提供了统一的访问接口。迭代器可以看作是 "广义指针",它使得算法可以独立于容器类型工作。 两者的核心关系 迭代器在很多方面模仿了指针的行为 指针可以看作是一种特殊的迭代器(用于原生数组) 所有指针都满足随机访问迭代器的要求 迭代器通常通过重载运算符来模拟指针的操作 代码示例指针与迭代器的基本使用对比123456789101112131415161718192021222324252627282930...
C++ 算法:remove_if 与 partition
一、remove_if 算法原理与实现细节1.1 核心功能与特性remove_if是 C++ 标准库中用于条件过滤的算法,它能移除容器中满足特定条件的元素。需要特别注意的是: 执行的是逻辑删除而非物理删除 不会改变容器的大小(size) 返回指向新的逻辑末尾的迭代器 1.2 底层实现逻辑123456789101112131415// 模拟标准库remove_if实现逻辑template<class ForwardIt, class UnaryPredicate>ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p) { // 跳过不符合删除条件的元素 first = std::find_if(first, last, p); if (first != last) { // 用后面的元素覆盖需要删除的元素 for (ForwardIt i = std::next(first); i != last; ++i) ...
C++ 智能指针与容器组合使用:std::unique_ptr 与 std::vector
一、基础概念与设计原理在 C++ 开发中,std::unique_ptr与std::vector组合是动态内存管理的常用方案,既灵活又安全。unique_ptr独占所有权的特性,使其与容器存储场景天然适配,容器全权负责指针生命周期。 二、完整实现示例1. 定义基础类定义Point类,包含虚析构函数以支持多态: 123456789101112131415161718#include <iostream>#include <vector>#include <memory> class Point {private: int x_; int y_;public: Point(int x = 0, int y = 0) : x_(x), y_(y) { std::cout << "Point构造: (" << x_ << "," << y_ << ")" << std::...
C++ 中使用splice( )函数实现LRU算法
导言LRU(Least Recently Used,最近最少使用)算法是一种常用的缓存淘汰策略,其核心思想是:当缓存空间满时,优先淘汰最近最少使用的元素。在 C++ 中,结合list容器的splice()函数可以高效实现 LRU 算法,因为splice()能以 O (1) 的时间复杂度调整元素位置,非常适合维护元素的访问顺序。 一、LRU 算法的核心需求实现 LRU 算法需要支持以下操作: 访问元素:如果元素存在于缓存中,将其标记为 “最近使用”;如果不存在,需要插入新元素。 插入元素:当缓存未满时直接插入;当缓存已满时,删除 “最近最少使用” 的元素后再插入新元素。 维护顺序:始终保持元素的排列顺序与访问时间相关(最近使用的在前端,最少使用的在末端)。 二、数据结构设计为了高效实现 LRU,我们需要两种数据结构配合: list容器:用于存储缓存元素,最近使用的元素放在链表头部,最少使用的放在尾部。 unordered_map容器:用于快速查找元素在list中的位置(存储元素键与list迭代器的映射),支持 O (1) 时间复杂度的查找。 示例数据结构定义: 1...
C++ 容器中的 sort () 与 splice ()
一、sort ():容器元素的排序利器sort()是 C++ 标准库中用于排序的函数,其核心功能是对容器中的元素进行升序或自定义规则排序。不过,并非所有容器都支持sort(),它仅适用于随机访问迭代器的容器(如vector、deque、array等),而像list、set等容器则有自己的排序方式。 1. 基本用法sort()的函数原型如下(以vector为例): 1234567#include <algorithm> // 需包含算法库// 升序排序(默认)sort(begin_iterator, end_iterator);// 自定义排序规则sort(begin_iterator, end_iterator, comparator); 其中,begin_iterator和end_iterator指定排序的范围(左闭右开),comparator是一个自定义的比较函数或 lambda 表达式,用于定义排序规则。 2. 实战示例 默认升序排序: 12345678910111213#include <vector>#include <algorith...
C++ 容器中の erase
一、erase 方法的功能定位vector 的 erase 方法是 STL 中用于从容器中移除元素的核心函数,其主要功能是: 从 vector 中删除单个元素或一段连续范围内的元素 调整容器大小以反映元素数量的变化 维护剩余元素的连续性和内存布局 返回一个迭代器,指向被删除元素的下一个元素 erase 方法是破坏性操作,会改变容器的状态和内部布局,同时可能影响现有迭代器的有效性。 二、迭代器参数的语法特征与使用场景vector 的 erase 方法有两种重载形式,分别适用于不同的删除场景: 2.1 单个元素删除1iterator erase(iterator position); 参数:指向要删除元素的迭代器 返回值:指向被删除元素下一个元素的有效迭代器 使用场景:已知要删除元素的确切位置时 2.2 范围元素删除1iterator erase(iterator first, iterator last); 参数: first:指向要删除范围中第一个元素的迭代器 last:指向要删除范围中最后一个元素之后位置的迭代器 返回值:指向最后一个被删除元素下一个元素...

