多態
一、概念
多態是指不同對象對同一消息產生不同響應的行為。例如,藍牙、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;
- 這是本人的學習筆記不是獲利的工具,小作者會一直寫下去,希望大家能多多監督我
- 文章會每攢夠兩篇進行更新發布
- 感謝各位的閱讀希望我的文章會對諸君有所幫助