【C++重載操作符與轉換】句柄類與繼承

目錄

一、句柄類的基本概念

1.1 什么是句柄類

1.2 句柄類的設計動機

1.3 句柄類的基本結構

二、句柄類的實現方式

2.1 基于指針的句柄類

2.2 值語義的句柄類

2.3 引用計數的句柄類

三、句柄類與繼承的結合應用

3.1 實現多態容器

3.2 實現插件系統

3.3 實現狀態模式

四、句柄類的優缺點

4.1 優點

4.2 缺點

五、句柄類與智能指針的比較

5.1 相似之處

5.2 不同之處

六、句柄類的設計考慮

6.1 復制控制

6.2 異常安全

6.3 虛函數表

6.4 接口設計

七、完整代碼示例

7.1 圖形庫示例?

7.2 文檔格式轉換器示例?

八、總結


在 C++ 面向對象編程中,句柄類 (Handle Class) 是一種強大的設計模式,它允許我們以統一的接口操作不同類型的對象,同時隱藏對象的具體實現細節。結合繼承和多態機制,句柄類可以實現靈活的對象管理,尤其適用于需要處理多種派生類對象的場景。

一、句柄類的基本概念

1.1 什么是句柄類

句柄類是一種包裝類,它封裝了對另一個對象 (通常是基類指針) 的訪問。句柄類的主要作用是提供一個統一的接口,隱藏底層對象的具體類型和實現細節,同時允許通過多態機制操作不同的派生類對象。

1.2 句柄類的設計動機

  • 解耦接口與實現:客戶端只需通過句柄類提供的接口操作對象,無需關心對象的具體類型和實現。
  • 管理對象生命周期:句柄類可以負責對象的創建、復制和銷毀,簡化資源管理。
  • 實現多態:句柄類內部通過基類指針或引用實現多態,允許在運行時動態綁定到不同的派生類對象。

1.3 句柄類的基本結構

一個典型的句柄類包含以下部分:

  • 一個指向基類的指針或引用
  • 構造函數,用于初始化底層對象
  • 復制控制函數 (拷貝構造函數、賦值運算符、析構函數)
  • 轉發調用到底層對象的成員函數
class Handle {
private:Base* ptr;  // 指向基類的指針
public:// 構造函數Handle(Base* p) : ptr(p) {}// 析構函數~Handle() { delete ptr; }// 拷貝構造函數Handle(const Handle& other);// 賦值運算符Handle& operator=(const Handle& other);// 轉發調用到底層對象void callMethod() { ptr->method(); }
};

二、句柄類的實現方式

2.1 基于指針的句柄類

最常見的句柄類實現方式是通過指針管理底層對象。這種方式允許句柄類在運行時動態綁定到不同的派生類對象。?

class Base {
public:virtual void print() const = 0;virtual ~Base() {}
};class Derived1 : public Base {
public:void print() const override { std::cout << "Derived1" << std::endl; }
};class Derived2 : public Base {
public:void print() const override { std::cout << "Derived2" << std::endl; }
};class Handle {
private:Base* ptr;
public:// 構造函數Handle(Base* p) : ptr(p) {}// 析構函數~Handle() { delete ptr; }// 拷貝構造函數 - 深拷貝Handle(const Handle& other) {if (other.ptr) {ptr = other.ptr->clone();  // 假設Base定義了純虛函數clone()} else {ptr = nullptr;}}// 賦值運算符Handle& operator=(const Handle& other) {if (this != &other) {delete ptr;if (other.ptr) {ptr = other.ptr->clone();} else {ptr = nullptr;}}return *this;}// 轉發調用void print() const {if (ptr) ptr->print();}
};

2.2 值語義的句柄類

值語義的句柄類在復制時會創建底層對象的副本,而不是簡單地復制指針。這種方式提供了更直觀的對象行為,但需要確保底層對象支持復制操作。?

class ValueHandle {
private:std::unique_ptr<Base> ptr;  // 使用智能指針管理內存
public:// 構造函數template<typename T>ValueHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}// 拷貝構造函數 - 深拷貝ValueHandle(const ValueHandle& other) {if (other.ptr) {ptr = other.ptr->clone();  // 調用虛函數clone()創建副本}}// 移動構造函數ValueHandle(ValueHandle&& other) noexcept = default;// 賦值運算符ValueHandle& operator=(ValueHandle other) {swap(*this, other);return *this;}// 交換函數friend void swap(ValueHandle& a, ValueHandle& b) noexcept {using std::swap;swap(a.ptr, b.ptr);}// 轉發調用void print() const {if (ptr) ptr->print();}
};

2.3 引用計數的句柄類

引用計數的句柄類通過維護一個引用計數來管理底層對象的生命周期,當最后一個引用被銷毀時才釋放對象。?

class RefCountHandle {
private:Base* ptr;int* count;  // 引用計數void acquire() {if (ptr) ++(*count);}void release() {if (ptr) {if (--(*count) == 0) {delete ptr;delete count;}}}
public:// 構造函數RefCountHandle(Base* p = nullptr) : ptr(p), count(new int(1)) {}// 拷貝構造函數RefCountHandle(const RefCountHandle& other) : ptr(other.ptr), count(other.count) {acquire();}// 賦值運算符RefCountHandle& operator=(const RefCountHandle& other) {if (this != &other) {release();ptr = other.ptr;count = other.count;acquire();}return *this;}// 析構函數~RefCountHandle() {release();}// 轉發調用void print() const {if (ptr) ptr->print();}
};

三、句柄類與繼承的結合應用

3.1 實現多態容器

句柄類可以用于實現多態容器,允許在同一個容器中存儲不同類型的對象。?

#include <iostream> 
#include <vector>
#include <memory>// 手動實現make_unique
#if __cplusplus < 201402L
namespace std {template<typename T, typename... Args>unique_ptr<T> make_unique(Args&&... args) {return unique_ptr<T>(new T(std::forward<Args>(args)...));}
}
#endifclass Shape {
public:virtual double area() const = 0;virtual ~Shape() {}
};class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}double area() const override { return 3.14 * radius * radius; }
};class Rectangle : public Shape {
private:double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}double area() const override { return width * height; }
};// 句柄類
class ShapeHandle {
private:std::unique_ptr<Shape> ptr;
public:template<typename T>ShapeHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}double area() const { return ptr->area(); }
};// 使用句柄類的多態容器
int main() {std::vector<ShapeHandle> shapes;shapes.emplace_back(Circle(5.0));shapes.emplace_back(Rectangle(3.0, 4.0));for (const auto& shape : shapes) {std::cout << "Area: " << shape.area() << std::endl;}return 0;
}

3.2 實現插件系統

句柄類可以用于實現插件系統,允許程序在運行時動態加載和使用不同的插件。?

// 插件接口
class Plugin {
public:virtual void execute() = 0;virtual ~Plugin() {}
};// 插件管理器
class PluginManager {
private:std::vector<std::unique_ptr<Plugin>> plugins;
public:// 加載插件template<typename T>void loadPlugin() {plugins.push_back(std::make_unique<T>());}// 執行所有插件void executeAll() {for (const auto& plugin : plugins) {plugin->execute();}}
};

3.3 實現狀態模式

句柄類可以用于實現狀態模式,允許對象在不同狀態之間切換,而不需要修改對象的接口。?

// 狀態接口
class State {
public:virtual void handle() = 0;virtual ~State() {}
};// 具體狀態
class ConcreteStateA : public State {
public:void handle() override { std::cout << "Handling state A" << std::endl; }
};class ConcreteStateB : public State {
public:void handle() override { std::cout << "Handling state B" << std::endl; }
};// 上下文類
class Context {
private:std::unique_ptr<State> state;
public:Context() : state(std::make_unique<ConcreteStateA>()) {}void setState(std::unique_ptr<State> newState) {state = std::move(newState);}void request() {state->handle();}
};

四、句柄類的優缺點

4.1 優點

  • 實現多態:句柄類通過基類指針或引用實現多態,允許統一處理不同類型的對象。
  • 解耦接口與實現:客戶端只需要與句柄類交互,不需要了解底層對象的具體類型和實現。
  • 簡化資源管理:句柄類可以負責對象的生命周期管理,減少內存泄漏的風險。
  • 提供值語義:通過適當的復制控制,句柄類可以提供值語義,使對象的行為更加直觀。

4.2 缺點

  • 性能開銷:虛函數調用和動態內存分配會帶來一定的性能開銷。
  • 實現復雜度:句柄類的實現需要處理復制控制、內存管理等復雜問題,容易引入錯誤。
  • 可能的內存碎片化:頻繁的動態內存分配和釋放可能導致內存碎片化。

五、句柄類與智能指針的比較

5.1 相似之處

  • 都用于管理動態分配的對象
  • 都提供了自動內存管理功能
  • 都可以通過基類指針實現多態

5.2 不同之處

  • 句柄類
    • 提供更高級的抽象,隱藏底層對象的具體類型
    • 可以自定義對象的復制和銷毀行為
    • 通常提供值語義
  • 智能指針
    • 主要關注內存管理
    • 提供標準的所有權語義(如 unique_ptr、shared_ptr)
    • 不隱藏底層對象的類型

六、句柄類的設計考慮

6.1 復制控制

句柄類必須正確處理復制控制(拷貝構造函數、賦值運算符和析構函數),以確保對象的生命周期得到正確管理。根據需求,可以實現深拷貝、引用計數或禁止復制。

6.2 異常安全

句柄類的操作應該是異常安全的,特別是在涉及動態內存分配和資源管理時。

6.3 虛函數表

使用句柄類時,需要確保基類定義了適當的虛函數,以便實現多態調用。

6.4 接口設計

句柄類的接口應該簡潔明了,只暴露必要的操作,隱藏底層實現細節。

七、完整代碼示例

7.1 圖形庫示例?

#include <iostream>
#include <memory>
#include <vector>// 手動實現 make_unique
#if __cplusplus < 201402L
namespace std {template<typename T, typename... Args>std::unique_ptr<T> make_unique(Args&&... args) {return std::unique_ptr<T>(new T(std::forward<Args>(args)...));}
}
#endif// 基類
class Shape {
public:virtual double area() const = 0;virtual std::string name() const = 0;virtual std::unique_ptr<Shape> clone() const = 0;virtual ~Shape() {}
};// 派生類
class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}double area() const override { return 3.14 * radius * radius; }std::string name() const override { return "Circle"; }std::unique_ptr<Shape> clone() const override {return std::make_unique<Circle>(*this);}
};class Rectangle : public Shape {
private:double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}double area() const override { return width * height; }std::string name() const override { return "Rectangle"; }std::unique_ptr<Shape> clone() const override {return std::make_unique<Rectangle>(*this);}
};// 句柄類
class ShapeHandle {
private:std::unique_ptr<Shape> ptr;
public:// 構造函數template<typename T>ShapeHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}// 拷貝構造函數ShapeHandle(const ShapeHandle& other) : ptr(other.ptr->clone()) {}// 移動構造函數ShapeHandle(ShapeHandle&& other) noexcept = default;// 賦值運算符ShapeHandle& operator=(ShapeHandle other) {swap(*this, other);return *this;}// 交換函數friend void swap(ShapeHandle& a, ShapeHandle& b) noexcept {using std::swap;swap(a.ptr, b.ptr);}// 轉發調用double area() const { return ptr->area(); }std::string name() const { return ptr->name(); }
};// 使用示例
int main() {// 創建句柄對象ShapeHandle circle(Circle(5.0));ShapeHandle rectangle(Rectangle(3.0, 4.0));// 使用句柄對象std::cout << circle.name() << " area: " << circle.area() << std::endl;std::cout << rectangle.name() << " area: " << rectangle.area() << std::endl;// 創建多態容器std::vector<ShapeHandle> shapes;shapes.push_back(circle);shapes.push_back(rectangle);// 遍歷容器for (const auto& shape : shapes) {std::cout << shape.name() << " area: " << shape.area() << std::endl;}return 0;
}

7.2 文檔格式轉換器示例?

#include <iostream>
#include <memory>
#include <string>// 手動實現 make_unique (C++11 適用)
#if __cplusplus < 201402L
namespace std {template<typename T, typename... Args>std::unique_ptr<T> make_unique(Args&&... args) {return std::unique_ptr<T>(new T(std::forward<Args>(args)...));}
}
#endif// 文檔接口
class Document {
public:virtual void convertToPDF() = 0;virtual void convertToWord() = 0;virtual ~Document() {}
};// Word文檔
class WordDocument : public Document {
public:void convertToPDF() override {std::cout << "Converting Word document to PDF..." << std::endl;}void convertToWord() override {std::cout << "Word document is already in Word format." << std::endl;}
};// PDF文檔
class PDFDocument : public Document {
public:void convertToPDF() override {std::cout << "PDF document is already in PDF format." << std::endl;}void convertToWord() override {std::cout << "Converting PDF document to Word..." << std::endl;}
};// 文檔句柄類
class DocumentHandle {
private:std::unique_ptr<Document> ptr;
public:template<typename T>DocumentHandle(T obj) : ptr(std::make_unique<T>(std::move(obj))) {}void convertToPDF() { ptr->convertToPDF(); }void convertToWord() { ptr->convertToWord(); }
};// 使用示例
int main() {DocumentHandle wordDoc{WordDocument()};DocumentHandle pdfDoc{PDFDocument()};wordDoc.convertToPDF();wordDoc.convertToWord();pdfDoc.convertToPDF();pdfDoc.convertToWord();return 0;
}

八、總結

句柄類是 C++ 中一種強大的設計模式,它結合了繼承和多態機制,提供了一種靈活且安全的方式來管理不同類型的對象。通過封裝底層對象的實現細節,句柄類可以實現接口與實現的解耦,簡化資源管理,并提供統一的操作接口。

在設計和實現句柄類時,需要注意以下幾點:

  1. 正確處理復制控制,根據需求選擇深拷貝、引用計數或禁止復制
  2. 使用智能指針管理動態內存,避免內存泄漏
  3. 確保基類定義了適當的虛函數,實現多態調用
  4. 設計簡潔明了的接口,隱藏底層實現細節
  5. 考慮異常安全性,確保操作在異常情況下也能正確釋放資源

通過合理運用句柄類,可以構建更加靈活、可維護的 C++ 程序,充分發揮面向對象編程的優勢。?


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80222.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80222.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80222.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

谷歌曾經的開放重定向漏洞(如今已經修復) -- noogle DefCamp 2024

題目描述: 上周&#xff0c;我決定創建自己的搜索引擎。這有點難&#xff0c;所以我背上了另一個。我也在8000端口上嘗試了一些東西。 未發現題目任何交互,但是存在一個加密js const _0x43a57f _0x22f9; (function(_0x3d7d57, _0x426e05) {const _0x16c3fa _0x22f9, _0x3187…

【C#】ToArray的使用

在 C# 中&#xff0c;ToArray 方法通常用于將實現了 IEnumerable<T> 接口的集合&#xff08;如 List<T>&#xff09;轉換為數組。這個方法是 LINQ 提供的一個擴展方法&#xff0c;位于 System.Linq 命名空間中。因此&#xff0c;在使用 ToArray 方法之前&#xff0…

資產管理平臺—chemex

1、簡介 Chemex CMDB&#xff08;Configuration Management Database&#xff09;是一個基于現代微服務架構的資產管理與自動化平臺&#xff0c;專為 IT 基礎設施與業務資產管理而設計。其核心目標是解決大規模系統運維中資產信息混亂、配置分散、數據不一致等問題&#xff0c…

【AI】mcp server是什么玩意兒

文章目錄 背景mcp server的必要性mcp server的基本概念mcp server的架構與核心組件總結 背景 劈里啪啦的整了一堆概念&#xff0c;對mcp server還是只停留在知道個詞的地步。 雖然目前大模型的對話生成能力很強&#xff0c;但是大模型&#xff08;如deepseek&#xff09;并不能…

c# 數據結構 樹篇 入門樹與二叉樹的一切

事先聲明,本文不適合對數據結構完全不懂的小白 請至少學會鏈表再閱讀 c# 數據結構 鏈表篇 有關單鏈表的一切_c# 鏈表-CSDN博客 數據結構理論先導:《數據結構&#xff08;C 語言描述&#xff09;》也許是全站最良心最通俗易懂最好看的數據結構課&#xff08;最遲每周五更新~~&am…

《Cookie Cutter》中2000多張精靈表與10000個2D光源的管理之道

一個小團隊如何在多個平臺上以優秀的效果展示手繪動畫&#xff1f;Subcult Joint 工作室給出了答案。他們用六年時間開發出了游戲《Cookie Cutter》。游戲中使用了數千個使用傳統動畫技術制作的高分辨率資產&#xff0c;而且這些資產都在 Unity 中進行了優化。由于工作室需要在…

什么是實景VR?實景VR應用場景

實景VR&#xff0c;即基于真實場景的虛擬現實技術&#xff0c;是利用計算機技術生成三維環境&#xff0c;以模擬并再現真實世界場景的技術。 用戶通過佩戴VR設備&#xff08;如VR頭盔、手柄等&#xff09;或通過電腦設備&#xff0c;可以沉浸在一個高度仿真的虛擬環境中&#…

內核性能測試(60s不丟包性能)

以xGAP-200-SE7K-L&#xff08;雙口10G&#xff09;在飛騰D2000上為例&#xff08;單通道最高性能約2.8Gbps) 單口測試 0口&#xff1a; tcp&#xff1a; taskset -c 4 iperf -c 1.1.1.1 -i 1 -t 60 -p 60001 taskset -c 4 iperf -s -i 1 -p 60001 udp&#xff1a; taskse…

58. 區間和

題目鏈接&#xff1a; 58. 區間和 題目描述&#xff1a; 給定一個整數數組 Array&#xff0c;請計算該數組在每個指定區間內元素的總和。 輸入描述 第一行輸入為整數數組 Array 的長度 n&#xff0c;接下來 n 行&#xff0c;每行一個整數&#xff0c;表示數組的元素。隨后…

C#進階(2)stack(棧)

前言 我們前面介紹了ArrayList,今天就介紹另一種數據結構——棧。 這是棧的基本形式,博主簡單畫了一下,你看個意思就行,很明顯,這種數據有一種特征:先進后出。因為先進來的數據會在下面,下面是密閉的,所以只能取后面進來的。 C#為我們封好了這種數據結構,我們不用擔…

汽車工廠數字孿生實時監控技術從數據采集到三維驅動實現

在工業智能制造推動下&#xff0c;數字孿生技術正成為制造業數字化轉型的核心驅動力。今天詳細介紹數字孿生實時監控技術在汽車工廠中的應用&#xff0c;重點解析從數據采集到三維驅動實現的全流程技術架構&#xff0c;并展示其在提升生產效率、降低成本和優化決策方面的顯著價…

git|gitee倉庫同步到github

參考&#xff1a;一次提交更新兩個倉庫&#xff0c;Get 更優雅的 GitHub/Gitee 倉庫鏡像同步 文章目錄 進入需要使用鏡像功能的倉庫&#xff0c;進入「管理」找到「倉庫鏡像管理」選項&#xff0c;點擊「添加鏡像」按鈕綁定github綁定成功后再次點擊添加鏡像如何申請 GitHub 私…

原生小程序+springboot+vue+協同過濾算法的音樂推薦系統(源碼+論文+講解+安裝+部署+調試)

感興趣的可以先收藏起來&#xff0c;還有大家在畢設選題&#xff0c;項目以及論文編寫等相關問題都可以給我留言咨詢&#xff0c;我會一一回復&#xff0c;希望幫助更多的人。 系統背景 在數字音樂產業迅猛發展的當下&#xff0c;Spotify、QQ 音樂、網易云音樂等音樂平臺的曲…

RustDesk

配置中繼服務器 https://rustdesk.com/docs/zh-cn/self-host/windows/ 服務器端 下載Windows版本 rustdesk-server-windows-x86_64.zip&#xff0c;安裝路徑為&#xff1a;C:\Program Files\RustDeskServer\bin。執行 hbbr.exe 和 hbbs.exe 兩個應用程序。這兩個應用提供了兩…

django中用 InforSuite RDS 替代memcache

在 Django 項目中&#xff0c;InforSuite RDS&#xff08;關系型數據庫服務&#xff09;無法直接替代 Memcached&#xff0c;因為兩者的設計目標和功能定位完全不同&#xff1a; 特性MemcachedInforSuite RDS核心用途高性能內存緩存&#xff0c;臨時存儲鍵值對數據持久化關系型…

leetcode 57. Insert Interval

題目描述 代碼&#xff1a;由于intervals已經按照左端點排序&#xff0c;并且intervals中的區間全部不重疊&#xff0c;那么可以斷定intervals中所有區間的右端點也已經是有序的。先二分查找intervals中第一個其右端點>newInterval左端點的區間。然后按照類似于56. Merge In…

去年開發一款鴻蒙Next Os的window工具箱

持拖載多個鴻蒙應用 批量簽名安裝 運行 http://dl.lozn.top/lozn/HarmonySignAndFileManagerTool_2024-11-26.zip 同類型安卓工具箱以及其他軟件下載地址匯總 http://dl.lozn.top/lozn/ 怎么個玩法呢&#xff0c;比如要啟動某app, 拖載識別到包名 點啟動他能主動讀取包名 然后…

Trivy:讓你時刻掌控的開源安全掃描器

深入了解 Trivy:全面的安全掃描工具 在如今互聯網快速發展的時代,軟件的安全性顯得尤為重要。隨著應用程序的復雜性增加,其可能帶來的安全漏洞也在不斷增多。如何快速、準確地發現這些潛在威脅是每個開發者和運維人員心中的課題。今天,我們將為大家介紹一個開源的安全掃描…

網址為 http://xxx:xxxx/的網頁可能暫時無法連接,或者它已永久性地移動到了新網址

這是由于瀏覽器默認的非安全端口所導致的&#xff0c;所謂非安全端口&#xff0c;就是瀏覽器出于安全問題&#xff0c;會禁止一些網絡瀏覽向外的端口。 避免使用6000,6666這樣的端口 6000-7000有很多都不行&#xff0c;所以盡量避免使用這個區間 還有在云服務器中&#xff0c…

Jenkins 執行器(Executor)如何調整限制?

目錄 現象原因解決 現象 Jenkins 構建時&#xff0c;提示如下&#xff1a; 此刻的心情正如上圖中的小老頭&#xff0c;火冒三丈&#xff0c;但是不要急&#xff0c;因為每一次錯誤&#xff0c;都是系統中某個環節在說‘我撐不住了’。 原因 其實是上圖的提示表示 Jenkins 當…