C++初登门槛
多态
一、概念
多态是指不同对象对同一消息产生不同响应的行为。例如,蓝牙、4G、Wi-Fi 对“发送数据”指令有不同的具体实现。
二、核心理解
-
本质:通过基类指针或引用操作子类对象,实现运行时动态绑定。
-
表现形式:
-
接口统一:基类定义通用接口(如
virtual void TransmitData()
)。 -
实现多样:子类重写接口,提供具体功能(如蓝牙发送数据的具体逻辑)。
-
三、分类与对比
类型 | 静态多态(早绑定) | 动态多态(晚绑定) |
---|---|---|
实现方式 | 函数重载、模板 | 虚函数(virtual ) |
绑定时机 | 编译期确定调用函数 | 运行时根据对象类型确定调用函数 |
灵活性 | 低(依赖编译时类型) | 高(支持运行时多态) |
四、作用与意义
-
通用性:将不同子类对象视为基类对象,编写统一代码。
SendData* devices[] = {new Bluetooth(), new A4G(), new WiFi()}; for (auto device : devices) { device->TransmitData(); // 统一接口,不同实现 }
-
扩展性:新增子类无需修改现有代码(如新增 ZigBee 模块)。
-
解耦:分离接口与实现,降低代码依赖性。
五、实现前提条件
-
继承关系:必须存在基类与子类的继承结构。
-
虚函数重写:基类方法用
virtual
声明,子类重写该方法。 -
基类引用/指针指向子类对象:通过基类操作实际子类对象。
六、实现步骤(以物联网设备为例)
-
定义基类虚函数:
class SendData { public: virtual void TransmitData() = 0; // 纯虚函数 virtual ~SendData() = default; // 虚析构函数 };
-
子类继承并重写虚函数:
class Bluetooth : public SendData { public: void TransmitData() override { cout << "蓝牙发送数据..." << endl; } };
-
使用基类指针操作子类对象:
int main() { SendData* device = new Bluetooth(); device->TransmitData(); // 动态调用 Bluetooth 的实现 delete device; return 0; }
七、应用场景示例(物联网设备数据传输)
-
需求:统一管理蓝牙、4G、Wi-Fi 的数据传输接口。
-
设计:
-
基类
SendData
定义虚函数TransmitData()
。 -
子类
Bluetooth
、A4G
、WiFi
分别实现具体传输逻辑。 -
客户端通过基类指针调用接口,无需关心具体设备类型。
-
八、注意事项
-
虚析构函数:基类必须声明虚析构函数,确保正确释放子类资源。
-
避免切片问题:使用指针或引用传递对象,而非值传递。
-
纯虚函数:若基类仅定义接口,可声明为纯虚函数(
= 0
),使基类成为抽象类。
代码示例:
//4G通讯
#include <iostream>
#include "send_data.h"
#include <cstring>
#ifndef __A4G__HEAD__
#define __A4G__HEAD__
using namespace std;
class A4G:public Send_data
{
private:char* data;
public:A4G(const char* data);void Transmit_data();virtual ~A4G();
};
//构造函数
A4G::A4G( const char* data)
{cout << "构造函数" << endl;this->data = new char[strlen(data) + 1]; // 分配内存strcpy(this->data, data); // 复制内容
}void A4G::Transmit_data(){cout << "用4G发送数据:" << this->data << endl;
}A4G::~A4G()
{cout << "~A4G" << endl;
}#endif
//蓝牙通讯
#include <iostream>
#include "send_data.h"
#include <cstring>
#ifndef __Blue_tooth__HEAD__
#define __Blue_tooth__HEAD__
using namespace std;
class Blue_tooth:public Send_data
{
private:char* data;
public:Blue_tooth(const char* data);void Transmit_data();virtual ~Blue_tooth();
};
//构造函数
Blue_tooth::Blue_tooth(const char* data)
{cout << "构造函数" << endl;this->data = new char[strlen(data) + 1]; // 分配内存strcpy(this->data, data); // 复制内容
}void Blue_tooth::Transmit_data(){cout << "用蓝牙发送数据:" << this->data << endl;
}Blue_tooth::~Blue_tooth()
{cout << "~Blue_tooth" << endl;delete []data;
}#endif // DEBUG
//WiFi通讯
#include <iostream>
#include "send_data.h"
#ifndef __Wifi__HEAD__
#define __Wifi__HEAD__
using namespace std;
class Wifi:public Send_data
{
private:char* data;
public:Wifi(const char* data);void Transmit_data();virtual ~Wifi();
};
//构造函数
Wifi::Wifi(const char* data)
{cout << "构造函数" << endl;this->data = new char[strlen(data) + 1]; // 分配内存strcpy(this->data, data); // 复制内容
}void Wifi::Transmit_data(){cout << "用Wifi发送数据:" << this->data << endl;
}Wifi::~Wifi()
{cout << "~Wifi" << endl;//delete []data;
}#endif // DEBUG
//主函数
#include "4G.h"
#include "bluetooth.h"
#include "send_data.h"
#include "wifi.h"
#include <iostream>int main(){
//——————————————————————————这里是使用指针——————————————————————————// A4G* fg = new A4G("今天天气良好") ;// fg->Transmit_data();// Blue_tooth* bt = new Blue_tooth("今天天气良好") ;// bt->Transmit_data();// Wifi* wf =new Wifi("今天天气良好") ;// wf->Transmit_data();
//__________________________这里使用引用——————————————————————————————\
//自动析构
A4G fg = A4G("今天天气良好") ;
fg.Transmit_data();
//自动析构
Blue_tooth bt = Blue_tooth("今天天气良好") ;
bt.Transmit_data();// Blue_tooth* bt = new Blue_tooth("今天天气良好") ;
// bt->Transmit_data();Wifi* wf =new Wifi("今天天气良好") ;
wf->Transmit_data();
delete wf;return 0;
}
多态实现原理
一、虚函数表(vtable)与虚指针(vptr)
核心机制
虚函数表(vtable):每个包含虚函数的类在编译时生成一个虚函数表,表中存储该类所有虚函数的地址。
虚指针(vptr):每个对象在内存中隐含一个指向其虚函数表的指针(
vptr
),用于运行时动态绑定。内存布局示例
class Hero { public:virtual void skill() {}string name;static int count; };
32位系统:
vptr
占4字节,string
占24字节(实现依赖),总大小4 + 24 = 28
字节(对齐可能调整)。64位系统:
vptr
占8字节,string
占32字节(实现依赖),总大小8 + 32 = 40
字节。调试验证(GDB)
调试程序
gdb a.out
设置断点
b 函数名/行号
运行调试
r
单步执行
n
- set print object on/off 是否以更易于阅读的方式打印结构体或类对象
- set print pretty on/off 控制数组打印
- set print array on 查看对象信息
- print object 数据显示格式
- x 按十六进制格式显示变量
- d 按照十进制格式显示变量
- u 按十六进制格式显示无符号整型
- o 按八进制格式显示变量
- t 按二进制格式显示变量
- a 按十六进制格式显示变量
- c 按字符格式显示变量
- f 按浮点数格式显示变量
虚函数表
-
虚函数表(vtable)是C++中实现多态性的核心机制,它存放了类中虚函数的入口地址。
-
_vptr是每个包含虚函数的类的对象中的一个隐藏指针,指向该类的虚函数表。
-
编译器自动生成和维护虚函数表以及_vptr,开发者无需手动干预。
-
在GDB中调试时,可以查看_vptr的值以及它所指向的虚函数表,以了解对象的多态行为。
二、继承与虚函数表覆盖
-
子类继承父类虚函数表
-
子类继承父类的虚函数表,若重写父类虚函数,则替换对应条目。
-
示例:
class Houyi : public Hero { public:virtual void skill() override {} };
-
子类
Houyi
的虚函数表中skill()
地址指向Houyi::skill()
。
-
-
-
调试验证
(gdb) print houyi $1 = (Houyi) {<Hero> = {_vptr.Hero = 0x56558e7c <vtable for Houyi+8>},looks = 20 }
三、静态绑定与动态绑定
特性 | 静态绑定 | 动态绑定 |
---|---|---|
绑定时机 | 编译期(根据类型确定调用) | 运行期(根据对象实际类型确定) |
实现方式 | 函数重载、模板 | 虚函数(virtual ) |
灵活性 | 低 | 高 |
关键区别:
-
动态绑定依赖虚函数表:通过
vptr
找到虚函数表,再根据实际对象类型调用对应函数。 -
多态场景:必须通过基类指针或引用操作子类对象。
四、32位与64位系统下的对象大小
-
基本规则
-
指针大小:32位系统4字节,64位系统8字节。
-
内存对齐:通常按最大成员类型对齐(如
int
按4字节对齐)。
-
-
复杂继承示例
class C : public A, public B {int c; };
-
32位系统:
-
A
含vptr
(4) +int a
(4) = 8字节。 -
B
含vptr
(4) +int b
(4) = 8字节。 -
C
含A
(8) +B
(8) +int c
(4) = 20字节(对齐到8的倍数→24字节)。
-
-
64位系统:
-
A
含vptr
(8) +int a
(4) → 对齐到8字节 → 16字节。 -
B
含vptr
(8) +int b
(4) → 对齐到8字节 → 16字节。 -
C
总大小:16 + 16 + 4 = 36 → 对齐到8的倍数→40字节。
-
-
六、总结
-
多态实现核心:虚函数表与虚指针的动态绑定机制。
-
内存管理关键:理解不同系统下的指针大小和对齐规则。
-
调试工具:GDB可用于验证虚函数表和对象内存布局。
-
设计原则:优先使用虚函数实现动态多态,避免手动管理内存错误。
重载、覆盖和隐藏
一、重载(Overloading)
定义:在同一作用域内定义多个同名函数或运算符,但参数列表(参数类型、数量或顺序)不同。
特点:
-
编译时多态,由编译器根据参数列表决定调用哪个函数。
-
适用于函数和运算符。
-
函数签名必须不同(返回类型不影响)。
-
const
修饰符、引用或指针类型的参数可区分重载。
示例:
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
二、覆盖(Overriding)
定义:派生类重新定义基类的虚函数,实现运行时多态。
条件:
-
基类函数必须为虚函数(
virtual
)。 -
函数签名(名称、参数列表、返回类型)完全相同。
-
访问权限可以不同,但通常保持一致。
特点:
-
通过基类指针或引用调用时,实际执行派生类的函数。
-
依赖虚函数表(vtable)实现动态绑定。
示例:
class Base {
public: virtual void show() { cout << "Base"; }
};
class Derived : public Base {
public: void show() override { cout << "Derived"; }
};
三、隐藏(Hiding)
定义:派生类中的成员(函数或属性)与基类同名,导致基类成员在派生类作用域中不可见。
类型:
-
函数隐藏:
-
派生类函数与基类函数同名但参数不同,或同名同参数但基类函数非虚。
-
基类函数被隐藏,需通过作用域解析符(
Base::func()
)访问。
-
-
属性隐藏:
-
派生类定义与基类同名的成员变量,直接访问时使用派生类版本。
-
示例:
class Base {
public: void func() { cout << "Base::func"; } int value;
};
class Derived : public Base {
public: void func(double) { cout << "Derived::func"; } // 隐藏Base::func() double value; // 隐藏Base::value
};
关键区别
特性 | 重载 | 覆盖 | 隐藏 |
---|---|---|---|
作用域 | 同一作用域 | 基类与派生类之间 | 基类与派生类之间 |
函数签名 | 必须不同 | 必须相同 | 可不同或相同(非虚) |
虚函数 | 不要求 | 必须为虚函数 | 不要求 |
多态性 | 编译时多态 | 运行时多态 | 无多态性 |
抽象类与泛型
一、抽象类(Abstract Class)
定义:
抽象类是一种不能被实例化的类,用于定义接口或基类,要求派生类必须实现其纯虚函数。
核心特点:
-
纯虚函数:
-
声明格式为
virtual 返回类型 函数名() = 0;
,无函数体。 -
派生类必须实现所有纯虚函数,否则派生类仍为抽象类。
class AbstractClass { public:virtual void pureVirtual() = 0; // 纯虚函数 };
-
-
不能实例化:
-
直接实例化抽象类会导致编译错误。
AbstractClass obj; // 错误:无法创建抽象类对象
-
-
基类作用:
-
抽象类通过指针或引用实现多态,指向派生类对象。
AbstractClass* ptr = new DerivedClass(); ptr->pureVirtual(); // 调用派生类的实现
-
-
构造与析构函数:
-
抽象类可以有构造函数和析构函数,但析构函数通常声明为虚函数以确保正确释放资源。
-
应用场景:
-
定义统一接口:要求所有派生类遵循相同的接口规范。
-
代码复用:基类提供公共逻辑,派生类实现具体功能。
示例:
class Shape { // 抽象类
public:virtual double area() = 0; // 纯虚函数virtual ~Shape() {} // 虚析构函数
};class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}double area() override { // 必须实现纯虚函数return 3.14 * radius * radius;}
};
二、泛型(Generics)
定义:
泛型编程通过模板(Templates)实现类型无关的代码,支持在编译时根据具体类型生成代码。
核心机制:
-
函数模板:
-
定义与类型无关的通用函数,支持多种数据类型。
template <typename T> T add(T a, T b) {return a + b; }
-
调用方式:
-
自动推导:
add(3, 4);
-
显式指定:
add<double>(3.14, 2.71);
-
-
-
类模板:
-
定义与类型无关的类,成员变量和函数的类型由模板参数决定。
template <typename T> class Box { private:T content; public:Box(T c) : content(c) {}T getContent() { return content; } };
-
-
模板继承:
-
派生类继承类模板时,需指定父类的具体类型或自身也声明为模板。
template <typename T> class Base { /* ... */ };class DerivedInt : public Base<int> { /* ... */ }; // 指定类型template <typename T1, typename T2> class DerivedTemplate : public Base<T2> { /* ... */ }; // 派生类模板
-
标准模板库(STL):
-
容器:如
vector
、list
、map
,用于存储和管理数据。vector<int> vec = {1, 2, 3}; for (int val : vec) cout << val << " ";
-
算法:如
sort
、find
,提供通用操作。sort(vec.begin(), vec.end());
应用场景:
-
通用数据结构:如链表、队列等,支持多种数据类型。
-
类型无关算法:如排序、查找,避免重复代码。
三、抽象类与泛型的对比
特性 | 抽象类 | 泛型 |
---|---|---|
核心目的 | 定义接口,强制派生类实现逻辑 | 编写类型无关的通用代码 |
多态性 | 运行时多态(虚函数) | 编译时多态(模板实例化) |
实例化限制 | 不能实例化抽象类 | 模板类/函数在实例化时生成具体代码 |
适用场景 | 面向对象设计中的继承与多态 | 需要支持多种数据类型的通用逻辑 |
四、关键总结
-
抽象类:
-
用于定义接口,强制派生类实现特定功能。
-
通过虚函数实现运行时多态,支持基类指针操作派生类对象。
-
-
泛型:
-
通过模板实现代码的通用性,避免重复逻辑。
-
在编译时生成类型相关代码,提高效率和灵活性。
-
-
结合使用:
-
抽象类和泛型可结合使用,例如定义泛型容器时,容器元素类型可以是抽象类的派生类。
-
示例代码:
// 抽象类与泛型结合
template <typename T>
class GenericContainer {
private:vector<T*> items;
public:void addItem(T* item) { items.push_back(item); }void processAll() {for (T* item : items) item->process();}
};class BaseItem { // 抽象类
public:virtual void process() = 0;virtual ~BaseItem() {}
};class DerivedItem : public BaseItem {
public:void process() override { /* ... */ }
};
顺序容器
一、顺序容器概览
顺序容器用于存储具有线性关系的元素,支持在任意位置插入、删除和访问元素。C++ STL 中的顺序容器包括:
容器 | 特性 | 优点 | 缺点 |
---|---|---|---|
vector | 动态数组,支持随机访问。 | 快速随机访问(O(1))。 | 中间插入/删除效率低(O(n))。 |
deque | 双端队列,支持两端高效操作。 | 两端插入/删除高效(O(1))。 | 中间操作效率低(O(n))。 |
list | 双向链表,任意位置插入/删除高效。 | 任意位置操作高效(O(1))。 | 不支持随机访问(O(n))。 |
forward_list | 单向链表(C++11),内存占用更小。 | 内存效率高。 | 仅支持单向遍历。 |
array | 固定大小数组(C++11)。 | 栈上分配,性能高。 | 大小不可变。 |
二、核心操作与成员函数
1. 通用操作
-
插入:
push_back
、push_front
(deque
、list
)、insert
。 -
删除:
pop_back
、pop_front
(deque
、list
)、erase
。 -
访问:
operator[]
、at
、front
、back
。 -
容量管理:
size
、resize
、capacity
、reserve
(vector
、deque
)。
2. 容器特有操作
容器 | 特有操作 |
---|---|
vector | shrink_to_fit (释放多余内存)。 |
deque | push_front 、pop_front 。 |
list | splice (合并链表)、merge (有序合并)、remove (删除特定值)。 |
forward_list | 仅提供单向迭代器,无 size() 函数。 |
三、性能对比与适用场景
场景 | 推荐容器 | 理由 |
---|---|---|
频繁随机访问 | vector 、array | 支持 O(1) 随机访问。 |
频繁两端操作 | deque | 两端插入/删除高效。 |
频繁任意位置插入/删除 | list | 链表结构无需移动元素。 |
内存敏感 | forward_list | 内存占用更小。 |
固定大小需求 | array | 编译时确定大小,无动态分配开销。 |
四、示例代码要点
1. vector
示例
vector<int> v1(3); // 初始化为3个0
v1.push_back(20); // 末尾添加元素
v1.insert(v1.begin()+2, 2, 30); // 在位置2插入两个30
-
注意:
vector
扩容时可能触发 2 倍内存分配,可通过reserve
预分配空间优化。
2. deque
示例
deque<int> d{1, 2, 3, 4};
d.push_front(200); // 头部插入200
d.push_back(50); // 尾部插入50
-
内存分布:由多个连续内存块组成,插入时无需整体复制。
3. list
示例
list<int> l = {7, 5, 16, 8};
l.push_front(25); // 头部插入25
l.remove(5); // 删除所有值为5的元素
-
不支持
operator[]
,需通过迭代器遍历。
关联容器
一、关联容器概览
关联容器通过平衡二叉树(红黑树)实现,元素按特定规则排序,提供高效的查找(O(log n))、插入和删除操作。主要包含以下四种容器:
容器 | 特性 | 适用场景 |
---|---|---|
set | 元素唯一,默认升序排列。 | 去重且需要有序访问的场景。 |
multiset | 允许重复元素,默认升序排列。 | 允许重复的有序集合。 |
map | 键值对(key-value),键唯一,按键排序。 | 键唯一且需按键快速查找的映射。 |
multimap | 键可重复,按键排序。 | 一键对应多值的映射。 |
二、核心特性与操作
1. set
与 multiset
-
共同点:
-
底层基于红黑树,元素自动排序。
-
支持插入(
insert
)、删除(erase
)、查找(find
)等操作。
-
-
区别:
-
set
元素唯一,multiset
允许重复。
-
-
示例代码:
set<int> s{1, 5, 3}; s.insert(2); // 插入元素,自动排序 s.erase(1); // 删除元素multiset<int> ms{1, 1, 3}; ms.insert(1); // 允许重复
2. map
与 multimap
-
共同点:
-
存储键值对,按键排序。
-
支持通过键快速查找值(
find
、operator[]
)。
-
-
区别:
-
map
键唯一,multimap
键可重复。
-
-
示例代码:
map<string, float> m; m["apple"] = 5.0; // 插入键值对 m.insert({"orange", 2.8});multimap<string, float> mm; mm.insert({"apple", 5.0}); mm.insert({"apple", 8.3}); // 允许重复键
3. 常用操作
-
插入:
s.insert(value); // set/multiset m.insert({key, value}); // map/multimap
-
删除:
s.erase(value); // 删除特定值 m.erase(key); // 删除特定键
-
查找:
auto it = s.find(value); // 返回迭代器 auto it = m.find(key); // 返回键对应的迭代器
-
遍历:
for (auto it = s.begin(); it != s.end(); ++it) {cout << *it << endl; // set/multiset } for (auto& [key, val] : m) {cout << key << ":" << val << endl; // map/multimap }
三、关键区别与选择
对比项 | set vs multiset | map vs multimap |
---|---|---|
元素唯一性 | set 唯一,multiset 可重复。 | map 键唯一,multimap 键可重复。 |
查找方式 | 直接按值查找。 | 按键查找值。 |
典型应用 | 去重集合、有序数据存储。 | 字典、配置表、多值映射。 |
四、高级操作与技巧
1. multimap
的多值键处理
-
equal_range
方法:查找所有匹配键的元素范围。auto range = mm.equal_range("apple"); for (auto it = range.first; it != range.second; ++it) {cout << it->second << endl; // 输出所有"apple"对应的值 }
2. 自定义排序规则
-
通过比较函数模板参数:
set<int, greater<int>> s; // 降序排列 map<string, int, Compare> m; // 自定义键比较规则
3. 性能优化
-
避免频繁插入/删除:红黑树的自平衡操作有开销。
-
使用
emplace
替代insert
:减少临时对象构造。
五、应用场景与实战
-
去重与排序:
-
使用
set
或map
自动去重并排序数据。
-
-
频率统计:
-
使用
map<string, int>
统计单词频率。
-
-
多值映射:
-
使用
multimap
存储学生ID到多个课程成绩的映射。
-
容器适配器、迭代器与函数对象
一、容器适配器
核心概念:
-
定义:基于现有容器封装,提供特定接口(如栈、队列)。
-
类型与底层实现:
-
stack
:默认基于deque
(支持高效首尾操作)。 -
queue
:默认基于deque
(避免空间浪费)。 -
priority_queue
:默认基于vector
(需连续内存构建堆)。
-
-
特性:
-
不直接支持迭代器,仅通过适配接口操作(如
push/pop
)。 -
priority_queue
默认大根堆,元素按优先级出队。
-
代码示例
queue
#include <iostream>
#include <queue>
using namespace std;
int main(){
queue<int> q;
q.push(17);
q.push(24);
q.push(86);
// 查看队首元素
cout << "queue front:" << q.front() << endl;
// 进行出队操作
while(!q.empty()){
cout << q.front() << endl;
q.pop();
}
return 0;
}
stack
#include <iostream>
#include <stack>
using namespace std;
int main(){
stack<int> s;
s.push(17);
s.push(24);
s.push(86);
// 查看栈顶元素
cout << "stack top:" << s.top() << endl;
// 进行出栈操作
while(!s.empty()){
cout << s.top() << endl;
s.pop();
}
return 0;
}
priority_queue
#include <iostream>
#include <queue>
using namespace std;
int main()
{priority_queue<int> pq;pq.push(36);pq.push(24);pq.push(86);// 查看队首元素cout << "queue front:" << pq.top() << endl;// 进行出队操作while (!pq.empty()){cout << pq.top() << endl;pq.pop();}
二、迭代器
核心概念:
-
作用:提供统一访问容器元素的接口,抽象底层实现(如链表、数组)。
-
实现关键:
-
重载操作符(
++
,*
,->
,==
,!=
)。 -
begin()
返回首元素迭代器,end()
返回尾后迭代器。
-
-
分类:
-
输入/输出迭代器、前向/双向/随机访问迭代器(STL容器支持不同类别)。
-
代码示例与修正:
-
自定义链表迭代器:
// 构造函数语法错误修正: iterator(ListNode<T> *ptr) : ptr(ptr) {} // 原代码缺少初始化列表 // 比较操作符修正: bool operator==(const iterator &other) const { return ptr == other.ptr; // 原代码中误写为 other_ptr }
应用场景:
-
泛型编程:STL算法(如
sort
,find
)通过迭代器操作任意容器。 -
遍历与修改:如
for (auto it = vec.begin(); it != vec.end(); ++it)
。
三、函数对象(仿函数)
核心概念:
-
定义:重载
operator()
的类实例,可像函数一样调用。 -
优点:
-
状态保存:成员变量记录调用间状态(如计数器)。
-
灵活性:可作为模板参数传递(如STL算法
sort
的比较器)。
-
-
STL内建函数对象:
-
算术:
plus<T>
,minus<T>
。 -
关系:
less<T>
,greater<T>
。 -
逻辑:
logical_and<T>
,logical_not<T>
。
-
代码示例与修正:
-
语法错误修正:
class SelfCompare { public:bool operator()(int n1, int n2) { // 原代码缺少括号闭合return n1 > n2;} };
应用场景:
-
STL算法:如
transform
使用仿函数对元素批量操作。 -
自定义策略:如排序规则、条件过滤(
find_if
)。
对比与联系
特性 | 容器适配器 | 迭代器 | 函数对象 |
---|---|---|---|
核心功能 | 封装特定数据结构接口 | 统一容器元素访问方式 | 封装可调用逻辑与状态 |
底层依赖 | 基于现有容器(如deque) | 依赖容器内部结构实现 | 独立类或STL内建对象 |
典型应用 | 栈、队列、优先队列 | 遍历、算法泛化 | 策略模式、STL算法参数 |
总结
-
容器适配器:通过封装简化特定数据结构操作,隐藏底层细节。
-
迭代器:实现容器与算法的解耦,是泛型编程的基石。
-
函数对象:提供灵活的可调用单元,优于函数指针(支持状态和内联优化)。
综合应用示例:
// 使用 priority_queue(适配器)+ 仿函数(自定义比较规则)
struct Compare {bool operator()(int a, int b) { return a > b; } // 小根堆
};
priority_queue<int, vector<int>, Compare> pq;
- 这是本人的学习笔记不是获利的工具,小作者会一直写下去,希望大家能多多监督我
- 文章会每攒够两篇进行更新发布
- 感谢各位的阅读希望我的文章会对诸君有所帮助
相关文章:
C++初登门槛
多态 一、概念 多态是指不同对象对同一消息产生不同响应的行为。例如,蓝牙、4G、Wi-Fi 对“发送数据”指令有不同的具体实现。 二、核心理解 本质:通过基类指针或引用操作子类对象,实现运行时动态绑定。 表现形式: 接口统一&a…...
【金仓数据库征文】- 金融HTAP实战:KingbaseES实时风控与毫秒级分析一体化架构
文章目录 引言:金融数字化转型的HTAP引擎革命一、HTAP架构设计与资源隔离策略1.1 混合负载物理隔离架构1.1.1 行列存储分区策略1.1.2 四级资源隔离机制 二、实时流处理与增量同步优化2.1 分钟级新鲜度保障2.1.1 WAL日志增量同步2.1.2 流计算优化 2.2 物化视图实时刷…...
SpringBoot 学习
什么是 SpringBoot SpringBoot 是基于 Spring 生态的开源框架,旨在简化 Spring 应用的初始化搭建和开发配置。它通过约定大于配置的理念,提供快速构建生产级应用的解决方案,显著降低开发者对 XML 配置和依赖管理的负担。 特点: …...
Q2桥门式起重机司机考试复习重点
Q2桥门式起重机司机考试复习重点 Q2桥门式起重机司机属于特种设备作业人员,理论考试重点复习时应重点掌握以下内容: 1、基础知识 桥门式起重机的结构组成(大车、小车、起升机构、电气系统等)。 主要技术参数(额定起…...
并发设计模式实战系列(7):Thread Local Storage (TLS)
🌟 大家好,我是摘星! 🌟 今天为大家带来的是并发设计模式实战系列,第七章Thread Local Storage (TLS),废话不多说直接开始~ 目录 一、核心原理深度拆解 1. TLS内存模型 2. 关键特性 二、生活化类比&a…...
本地使用Ollama部署DeepSeek
以下是在本地使用Ollama部署DeepSeek的详细教程,涵盖安装、修改安装目录、安装大模型以及删除大模型的操作步骤。 安装Ollama 1. 系统要求 确保你的系统满足以下条件: 操作系统:macOS、Linux或者Windows。足够的磁盘空间和内存。 2. 安装…...
通过VSCode远程连接到CentOS7/Ubuntu18等老系统
通过VSCode远程连接到CentOS7/Ubuntu18等老系统 背景 VSCode的远程连接插件Remote SSH一直以来是简单好用的远程工具。然而,2025年2月之后的版本在远程安装vscode-server时,预编译的server依赖glibc 2.28,这就要求Linux远程机的glibc版本应…...
Python在AI虚拟教学视频开发中的核心技术与前景展望
Python在AI虚拟教学视频开发中的核心技术与前景展望 一、引言:AI虚拟教学的技术革新 随着教育数字化转型加速,AI虚拟教学视频凭借个性化、沉浸式体验成为教育科技的新风口。Python以其强大的多模态处理能力、丰富的开源生态和跨领域兼容性,成…...
【金仓数据库征文】金仓数据库:开启未来技术脑洞,探索数据库无限可能
我的个人主页 我的专栏: 人工智能领域、java-数据结构、Javase、C语言,希望能帮助到大家!!! 点赞👍收藏❤ 目录 引言:数据库进化的下一站 —— 未来科技的无限可能金仓数据库简介:国…...
深入掌握Redis主从复制:原理、配置与生产级实践指南
一、主从复制核心价值与适用场景 1.1 核心价值矩阵 数据安全:多节点冗余存储,避免单点数据丢失 服务可用性:主节点故障时可快速切换从节点 性能扩展:通过横向扩展从节点提升读吞吐量 运维便利:从节点可承担备份、分…...
springboot如何管理多数据源?
静态多数据源管理 配置多个数据源 :创建多个数据源的配置类,通常使用 @ConfigurationProperties 注解来绑定配置文件中的数据源属性,并通过 @Bean 注解定义多个 DataSource Bean 。例如: 配置类: @Configuration public class DataSourceConfig {@Bean(name = "prima…...
基于风力推进器控制的小球实验装置设计与研究
目录 完整论文下载链接放在文章结尾,有需要自行下载。 目录 摘 要 1 引 言 2 概述 2.1 风控小球系统概述 2.2 本设计方案思路 2.3 研发方向和技术关键 2.4 主要技术指标 3 总体设计 4 硬件设计 4.1 单片机最小系统 4.2 供电接口电路 4.3 Openmv摄像头…...
Swift闭包(Closure)深入解析与底层原理
前言 在Swift开发中,闭包是一个非常重要且强大的特性。本文将深入探讨Swift闭包的底层实现原理,帮助开发者更好地理解和使用这一特性。 1. 什么是闭包 闭包是自包含的函数代码块,可以在代码中被传递和使用。它不仅可以像函数一样执行代码&…...
【DE-III】基于细节增强的模态内和模态间交互的视听情感识别
abstract 在视听情感识别(AVER)中,捕捉视频和音频模态之间复杂的时间关系是至关重要的。然而,现有的方法缺乏对局部细节的关注,如视频帧之间的面部状态变化,这会降低特征的可区分性,从而降低识别准确率。 为此,本文提出了一种用于AVER的细节增强的模态内和模态间交互…...
c++11 :智能指针
目录 一 为什么需要智能指针? 二 智能指针的使用及原理 1. RAII 2. auto_ptr 3. unique_ptr 4. shared_ptr 5. weak_ptr 三 内存泄漏 1.什么是内存泄漏,内存泄漏的危害 2. 如何避免内存泄漏? 一 为什么需要智能指针? …...
Linux解压tar.gz包的正确姿势(附赠防抓狂指南)
一、为什么你的解压命令总报错? 每次看到.tar.gz后缀是不是心里一紧?(别装了!我都看到你偷偷打开浏览器查命令的样子了)这个在Linux界横行霸道的压缩格式,其实用对了方法比Windows的zip还简单。今天咱们不…...
MCP协议:让AI从“话痨”变“实干家”的神奇魔法
一、MCP 协议:AI 界的 “万能插头” 是啥来头? 1.1 从 “动口不动手” 到 “全能打工人” 你以为 AI 只会陪你聊天、写文案?那你可小瞧它啦!MCP 协议(Model Context Protocol),堪称 AI 的 “瑞…...
如何在SpringBoot中通过@Value注入Map和List并使用YAML配置?
在SpringBoot开发中,我们经常需要从配置文件中读取各种参数。对于简单的字符串或数值,直接使用Value注解就可以了。但当我们需要注入更复杂的数据结构,比如Map或者List时,该怎么操作呢?特别是使用YAML这种更人性化的配…...
记一次调用大华抓拍SDK并发优化
目录 一、问题分析 二、解决思路 三、贴代码 四、总结 一、问题分析 按惯例上问题: 设备告警采用高电平持续模式:一次开,不主动关就一直处于告警状态。 并发时多个请求下发 setDVRAlarmOutConfig,导致状态混乱。 “开 -&g…...
打破认知!没论文没竞赛,我的暑期实习上岸秘籍:简历要敢 “吹”,面试靠巧 “聊”
前言 以下教程仅针对本人的大大小小几十场暑期实习面试的经验总结,个人背景(双9,无论文、无竞赛、无大厂实习、无奖。)。简历几易其稿,相对于原来的初版,可谓是脱胎换骨,洗经易髓。 二月中旬开…...
为何 RAG 向量存储应优先考虑 PostgreSQL + pgvector 而非 MySQL?
构建检索增强生成(RAG)系统已成为释放大型语言模型(LLM)潜力的关键范式。通过将 LLM 的推理能力与外部知识库的实时、特定信息相结合,RAG 能够生成更准确、更相关、更值得信赖的回答。而这个“外部知识库”的核心&…...
LangChain LCEL表达式语言简介
LangChain表达式语言(LCEL)是专为构建AI应用链设计的声明式编程框架,通过管道符|实现组件无缝衔接,支持流式处理、异步调用等生产级特性。其核心优势在于零代码改动实现原型到生产的过渡,同时保持代码简洁性和可维护性…...
智能座舱背后的秘密:智能座舱测试如何“具身智能”
在上期文章《智能座舱背后的秘密:AI赋能测试如何改写驾乘体验》中,我们聊到了“智能座舱”已成为车企争夺用户心智的核心战场、智能座舱功能体验进化、AI赋能座舱测试将突破“场景覆盖、情感量化、角色/场景衍生”技术实现方面的三大困局,并在…...
鸿蒙-试一下属性字符串:除了Span之外,如何在同一个Text组件中展示不同样式的文字
文章目录 前言简介有哪些类型拉出来溜溜Text SpanStyledString其他CustomSpan先看一下构造函数onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetricsonDraw(context: DrawContext, drawInfo: CustomSpanDrawInfo) 遗留问题 前言 在开发中,经常会遇到…...
今日最新漂亮的早上好图片祝福,最真的牵挂,永远的祝福
1、清晨的一个问候给你一个新的心情、一个祝福带给你新的起点、一个关心带给你一个新的愿望。祝福你心中常有快乐涌现!早安! 2、人过花甲万事休,唯有健康不可丢,荣华富贵皆浮云,逍遥自在渡岁月!时光匆匆&am…...
MySQL 库的操作 -- 增删改查,备份和恢复,系统编码
文章目录 库的操作增删改查数据库的查看和创建查看当前位于哪个数据库中数据库的删除总结显示数据库的创建语句修改数据库 认识系统编码数据库的编码问题查看系统默认的字符集和效验规则校验规则对数据库的影响 数据库的备份和恢复备份还原备份的是一张表 查看数据库的连接情况…...
【c++11】c++11新特性(下)(可变参数模板、default和delete、容器新设定、包装器)
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C 目录 前言 五、可变参数模板 1. 概念及简单定义 2. 包扩展 六、 default和delete 七、容器新设定 1. 新容器 2. 新接口 emplace系列接口 八、函数包…...
fps项目总结:生成武器子弹
文章目录 spawn actor:生成武器固定生成:因为武器的碰撞设为noCollision attach actor to component:将武器附加到骨骼上,成为mesh的子组件对齐到目标:对齐到插槽 子弹阻挡的前提是根组件为碰撞体子弹对碰撞体全是阻挡…...
大模型备案对模型训练语料的要求
昨天接到一位客户的咨询,说他们的模型还在开发阶段,想提前了解一下大模型备案政策中对于模型训练语料有什么具体要求,提前规避一下。客户确实有前瞻性,考虑得比较充分。训练语料在研发阶段至关重要,直接影响模型的性能…...
Ethan独立开发产品日报 | 2025-04-24
1. Peek AI个人财务教练,帮助你做出决策。 Peek的人工智能助手提供主动的跟踪服务——它会分析你的消费习惯,并以细腻而积极的方式帮助你调整这些习惯。没有评判,也没有负担。就像是为你的财务量身定制的Spotify Wrapped,完美贴…...
egg环境搭建
前言 egg.js 是由阿里开源的面向企业级开发的 Node.js 服务端框架,它的底层是由 Koa2 搭建。 Github:https://github.com/eggjs/egg,目前 14.8K Star,egg 很适合做中台。 安装 首先,你要 确保 Node 已经配置环境变量…...
Linux的基础指令
目录 1、Shell及运行原理 2、热键 3、Linux的基础知识 4、Linux的基础指令 4.1 man 4.2 clear&&history&&whoami 4.3 pwd 4.4 ls 4.5 cd 4.6 mkdir&&touch 1. mkdir 2. touch 4.7 rmdir&&rm 1. rmdir 2. rm 4.8 cp&&mv…...
第一部分:git基本操作
目录 1、git初识 1.1、存在的问题 1.2、版本控制器 1.3、git安装 1.3.1、CentOS平台 1.3.2、ubuntu平台 2、git基本操作 2.1、创建仓库 2.2、配置git 3、工作区、暂存区、版本库 4、基本操作 4.1、场景一 4.2、场景二 4.3、修改文件 5、版本回退 6、撤销修改 …...
Kafka和其他组件的整合
Kafka和其他组件的整合 1.Kafka和Flume的整合 需求1:利用flume监控某目录中新生成的文件,将监控到的变更数据发送给kafka,kafka将收到的数据打印到控制台: 在flume/conf下添加.conf文件, vi flume-kafka.conf # 定…...
学习AI必知的20大概念
🎯AI开发者必知的20大概念 🤖 机器学习:基础算法和模型训练。 🧠 深度学习:复杂表示学习。 🌐 神经网络:非线性关系建模。 🗣️ NLP:文本处理和理解。 👁️…...
VRRP与防火墙双机热备实验
目录 实验一:VRRP负载均衡与故障切换 实验拓扑编辑一、实验配置步骤 1. 基础网络配置 2. VRRP双组配置 二、关键验证命令 1. 查看VRRP状态 2. 路由表验证 三、流量分析 正常负载均衡场景: 故障切换验证: 实验二:防火…...
【金仓数据库征文】——选择金仓,选择胜利
目录 第一部分:金仓数据库——开创数据库技术的新时代 1.1 金仓数据库的技术底蕴 1.2 高可用架构与灾备能力 1.3 分布式架构与弹性扩展能力 第二部分:金仓数据库助力行业数字化转型 2.1 电信行业:核心系统国产化替代 2.2 医疗行业&…...
微软官网Win10镜像下载快速获取ISO文件
如何从微软官网轻松下载win10镜像?win10镜像的下载方式主要包括两种: 目录 一:借助官方工具 二:直接微软官网通过浏览器进行下载。 三:实现方法与步骤: 1:利用微软官方提供的MediaCreationT…...
发放优惠券
文章目录 概要整体架构流程技术细节小结 概要 发放优惠券 处于暂停状态,或者待发放状态的优惠券,在优惠券列表中才会出现发放按钮,可以被发放: 需求分析以及接口设计 需要我们选择发放方式,使用期限。 发放方式分…...
【专题刷题】二分查找(二)
📝前言说明: 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码;ÿ…...
如何避免IDEA每次打开新项目都重复配置Maven?
每次打开新项目都要重新设置Maven路径?每次导入工程都要手动调整settings.xml?如果你也受够了IDEA这种“健忘”行为,那么这篇文章就是为你准备的!今天我们就来彻底解决这个问题,让IDEA记住你的Maven配置,一…...
【Linux网络编程】应用层协议HTTP(实现一个简单的http服务)
目录 前言 一,HTTP协议 1,认识URL 2,urlencode和urldecode 3,HTTP协议请求与响应格式 二,myhttp服务器端代码的编写 HTTP请求报文示例 HTTP应答报文示例 代码编写 网络通信模块 处理请求和发送应答模块 结…...
深度解析之算法之分治(快排)
44.颜色分类 题目链接 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 必须在不使用库内置…...
【金仓数据库征文】-金仓数据库性能调优 “快准稳” 攻略:实战优化,让数据处理飞起来
我的个人主页 我的专栏: 人工智能领域、java-数据结构、Javase、C语言,希望能帮助到大家!!! 点赞👍收藏❤ 目录 一、KingbaseES金仓数据库简介二、快速入门:金仓数据库下载与安装指南三、“快”…...
DPIN河内AI+DePIN峰会:共绘蓝图,加速构建去中心化AI基础设施新生态
近日,一场聚焦前沿科技融合的盛会——AIDePIN峰会在越南河内成功举办。此次峰会由DPIN、QPIN及42DAO等Web3领域的创新项目联合组织,汇聚了众多Web3行业领袖、技术专家与社区成员。峰会于2025年4月19日举行,其核心议题围绕去中心化物理基础设施…...
vscode和git 踩坑
git init经常 在 vscode push错误问题: 正确姿势:先 GitHub 上建仓库 → git clone 拉到本地 → 再用 VSCode 打开编辑 ❌ 不是:VSCode 里 git init → 再去 GitHub 选个仓库绑定 举个对比 操作流程是否推荐后果GitHub 创建仓库 → git clone → 用 VSC…...
C++11介绍
目录 一、C11的两个小点 1.1、decltype 1.2、nullptr 二、列表初始化 2.1、C98传统的{} 2.2、C11中的{} 2.3、C11中的std::initializer_list 三、右值引用和移动语义 3.1、左值和右值 3.2、左值引用和右值引用 3.3、引用延长生命周期 3.4、左值和右值的参数匹配 3…...
AI数字人:繁荣背后的伦理困境与法律迷局(8/10)
摘要:本文深入剖析 AI 数字人从虚拟走向现实的历程,阐述其融合多技术实现从静态到动态交互的跨越,爆发式应用于各领域带来的商业价值与社会影响,同时直面由此引发的伦理法律挑战,包括身份认同、数据隐私、责任归属及权…...
SOLID 原则在单片机环境下的 C 语言实现示例,结合嵌入式开发常见场景进行详细说明
1. 单一职责原则 (SRP) 定义:一个模块(函数/文件)只负责一个功能。 示例:传感器数据采集与处理分离 // SensorAdc.h - 仅负责ADC原始数据采集 typedef struct { uint16_t (*ReadRaw)(void); // 原始数据读取接口 } SensorAdc; // SensorProcessor.h - 仅负责数据处理…...
RT Thread 发生异常时打印输出cpu寄存器信息和栈数据
打印输出发生hardfault时,当前栈十六进制数据和cpu寄存器信息 在发生 HardFault 时,打印当前栈的十六进制数据和 CPU 寄存器信息是非常重要的调试手段。以下是如何实现这一功能的具体步骤和示例代码。 1. 实现 HardFault 处理函数 我们需要在 HardFault 中捕获异常上下文,…...