奇异递归模板模式 CRTP
CRTP 的用途CRTP (Curiously Recurring Template Pattern) 主要用于实现静态多态。与 C++ 中常见的虚函数(virtual function)实现的动态多态不同,CRTP 在编译时解析函数调用,因此没有运行时开销。 举例假设我们想创建一个通用的基类,它可以计算任何派生类的面积,只要派生类提供一个 getArea() 方法。 例子:计算几何图形的面积首先,我们定义一个CRTP基类模板 Shape。这个基类有一个方法 calculateAndPrintArea(),它的任务是调用派生类中实现的 getArea() 方法,并打印结果。 1234567891011121314151617#include <iostream>template <typename Derived>class Shape {public: void calculateAndPrintArea() const { // 使用 static_cast 将基类指针转换为派生类指针。 // 这就...
this auto&& self 详解
好的,我们来详细解读这句 C++23 的新语法:auto&& operator[](this auto&& self, int index)。 这句代码定义了一个类的下标操作符(operator[]),但它使用了两个 C++23 的新特性,使其变得非常通用和强大: 显式 this 参数 (this auto&& self) 推导返回类型 (auto&&) 让我们一步步分解来理解。 核心功能:定义下标操作符 []首先,这句代码的本质是重载(overload)下标操作符 []。这允许类的对象可以像数组一样使用方括号来访问成员。例如,如果你有一个名为 MyArray 的类,定义了这个操作符后,你就可以这样写: 123MyArray arr;// ...auto value = arr[5]; // 这会调用 MyArray::operator[] 1. this auto&& self:显式 this 对象参数这是 C++23 引入的一个重要特性,被称为 “Deducing this“。 在传统的...
引用包装器
std::reference_wrapper 是 C++ 标准库 <functional> 头文件中的一个类模板,它的主要作用是将引用包装成一个可拷贝、可赋值的对象。 1. 什么是 std::reference_wrapper?在 C++ 中,引用(reference)本身不能被重新赋值,也不能作为容器的元素,因为它们不符合大多数标准库容器和算法对**可拷贝(Copyable)或可赋值(Assignable)**的要求。 std::reference_wrapper<T> 解决了这个问题。它内部持有一个 T 类型的引用,但它本身是一个对象,可以像普通对象一样被拷贝和赋值。当你拷贝一个 std::reference_wrapper 对象时,你拷贝的是对同一个原始对象的引用,而不是拷贝原始对象本身。 2. 为什么需要它?std::reference_wrapper 的主要用途是让引用能够与标准库容器和算法协同工作。 许多标准库组件,比如 std::vector、std::list、std::thread、std::sort 等,要求其操作的对象是可拷贝的。如果...
移动语义
C++ 移动语义:深入解析核心概念与优势在 C++11 标准中,移动语义 (Move Semantics) 是一项革命性的新增特性,其核心思想在于避免不必要的内存拷贝,通过“窃取”或“转移”资源的所有权来提升程序性能。这在处理大型数据结构,如容器、字符串或任何持有动态分配内存的类时,效果尤为显著。 为何需要移动语义?问题的根源:深拷贝在 C++11 之前,对象的复制是通过拷贝构造函数和拷贝赋值运算符完成的。当对象内部含有指针,指向动态分配的资源(如堆内存)时,为了确保新旧对象各自拥有一份独立的资源,必须进行深拷贝。 例如,考虑一个简单的字符串类: 123456789101112131415161718192021222324class MyString {public: MyString(const char* s = "") { size_ = strlen(s); data_ = new char[size_ + 1]; strcpy(data_, s); } // ...
左值和右值详解
C++ 的左值(lvalue)和右值(rvalue)是 C++ 语言中一个非常基础但又极其重要的概念。它们是 C++ 表达式(expression)的两种基本属性,深刻地影响着代码的性能和写法,尤其是在 C++11 标准引入“移动语义”(Move Semantics)之后。 简单来说,区分左值和右值的核心标准是:这个表达式所代表的数据,我们还能不能在后面的代码里再次访问到它。 左值 (lvalue - locator value):指那些在内存中有固定地址、可以被取地址(用 & 运算符)并且在表达式结束后依然存在的表达式。你可以把它想象成一个有名字、有固定地址的“容器”。 右值 (rvalue - read value):指那些临时的、没有固定地址、在表达式结束后就会被销毁的表达式。你只能读取它的值,但不能对它取地址(通常情况下)。可以把它看作一个“即用即弃”的临时数据。 一、从“赋值操作符”的左右看起(经典 C++98 时代)在 C++ 的早期,最简单的区分方法是看它能否出现在赋值操作符 = 的左边: 能放在 = 左边的,就是左值。 因为放在左边意味着你要给...
组合和聚合的区别
组合(Composition)组合是一种强拥有关系,表示“部分”是“整体”的生命周期的一部分。如果整体被销毁,那么它的所有部分也会被自动销毁。 可以把组合想象成一个房子和它的墙壁。你不能把墙壁从房子里拿出来,让它们独立存在。如果房子被拆除,墙壁也就不复存在了。 主要特点: 强生命周期依赖: 部分对象的生命周期由整体对象控制。 独占拥有: 一个部分只能属于一个整体。 创建关系: 通常,整体对象负责创建其部分对象。 示例: 123456789101112131415161718192021222324252627282930313233343536373839#include <iostream>#include <string>// 部分类:引擎class Engine {private: std::string type;public: Engine(std::string t) : type(t) { std::cout << "Engine (" << ...
Shell脚本基础
注意:在本文中,不以 #!/bin/bash 开头的代码均为伪代码或命令,仅供示意。 Hello World123#!/bin/bash# 上面一行称为 shabang,为的是直接执行脚本的时候能使用正确的解释器echo "Hello, world!" 使用以下命令来检查语法错误: 1bash -n ./xxx.sh 没有错误将不会有任何输出,执行脚本可以通过以下命令: 123bash ./xxx.sh # 直接指定解释器来执行# orchmod +x ./xxx.sh && ./xxx.sh # 把脚本赋予可执行权限后直接执行 使用变量和注释1# 这是一个注释,不会被执行 获取变量的值: 1234#!/bin/bashecho $BASH # '$'加变量名用于获取变量值# 全大写的一般为系统变量,用户自行定义的变量一般写成全小写形式# 如 '$HOME $PATH $PWD' 定义一个变量: 1name=Mark 使用这个变量: 1echo The name is $name 读取...
CAN理论基础
概述CAN 定义了物理层(Physical)和数据链路层(DataLink) 物理层:规定引脚数、如何定义0和1等等 数据链路层:如何定义一个CAN帧 物理层特性包括 包括 CAN_Low 和 CAN_High 两个线 逐位总线仲裁 双绞线,差分信号 电平 0为显性,1为隐性,即0可以把1覆盖了 按位仲裁 可以理解0的优先级比1高,即数字越小优先级越高;节点A它发送了1却检测到了0,那它就会停止发送了,因为有优先级更高的设备在传输 数据链路层(帧)共有三种类型: 其中**错误帧、过载帧、帧间隔**都是由硬件完成的,没有办法用软件来控制。 数据帧和遥控帧有**标准格式与扩展格式。标准格式有11位标识符,扩展格式有29位**标识符。 数据帧 远程帧 错误帧 数据帧 包括 1 帧起始 表示帧的开始,产生一个bit的显性电平。 2 仲裁段 表示帧的优先级, 由标识符(ID)和传送帧类型(RTR)组成。 3 控制端 表示数据的字节数,由6个bit构成(4bits为DLC 0~8bytes)。IDE位用于表明此帧是标准帧还是扩展帧。 4 数据段 数据的具体...
C语言细枝末节
数据相关16位操作系统:long:4字节,int:2字节 32位操作系统:long:4字节,int:4字节 64位操作系统:long:8字节,int:4字节 所以最好使用 stdint 内的指定位数的定义(如int8、int32等)保证移植的兼容性 声明 用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化(告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据) static全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。 在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。 static 修饰全局变量的时候,这个全局变量只能...
UART理论基础
基本概念 串行通信:数据一位一位按时间顺序发送(与并行通信相对)。 异步(Asynchronous):发送端和接收端不共享时钟线,而是通过预先约定的波特率(baud rate)和帧格式来同步数据采样。 物理连接与信号 常见的信号线:TX(发)和 RX(收),通常两设备交叉连接(A的TX接B的RX)。 电平标准:常见TTL电平(0V ~ 5V 或 0V ~ 3.3V)和RS-232(-3~-15V表示 1 ,+3~+15V表示 0 )等。不同电平不可直接连接,需电平转换器(如 MAX232)。 差分连接:RS485差分连接(TX 包括 TXD-、TXD+,以此类推),当两条差分线之间压差为正时(如+2V~+6V)为逻辑1,反之 协议 起始位:通信以发送方发送逻辑0为开始(空闲时为高电平),同时这也是为了同步采样周期。 数据位:可以为 5~8 bit,最低位优先 奇偶校验位:可以为 关闭(0 bit) 奇校验(odd parity):数据位的1的个数为偶,则该位为1,反之 偶校验(even parity):数据位的1的个数为偶,则该位为0,反之 停止位...