More Effective C++ 條款25:將構造函數和非成員函數虛擬化

More Effective C++ 條款25:將構造函數和非成員函數虛擬化


核心思想通過虛擬構造函數和非成員函數,實現運行時的多態行為,允許在不知道對象具體類型的情況下創建新對象或執行操作,增強代碼的靈活性和擴展性。

🚀 1. 問題本質分析

1.1 虛擬構造函數的必要性

  • 運行時類型創建:需要在運行時根據條件或數據創建不同類型的對象
  • 對象復制多態:復制對象時保持多態特性,根據實際類型創建新對象
  • 工廠模式基礎:為創建相關對象家族提供統一接口

1.2 虛擬非成員函數的應用場景

  • 多態IO操作:根據對象實際類型進行不同的序列化/反序列化
  • 通用算法適配:讓通用算法能夠適應不同派生類的特定行為
  • 運算符重載擴展:為多態對象提供自然的運算符使用方式
// 基礎示例:虛擬構造函數需求
class Shape {
public:virtual ~Shape() = default;// 虛擬構造函數模式:克隆方法virtual Shape* clone() const = 0;// 虛擬構造函數模式:創建方法virtual Shape* create() const = 0;
};class Circle : public Shape {
public:Circle* clone() const override {return new Circle(*this);  // 調用拷貝構造函數}Circle* create() const override {return new Circle();  // 調用默認構造函數}
};

📦 2. 問題深度解析

2.1 虛擬構造函數實現模式

// 原型模式實現虛擬構造函數
class Document {
public:virtual ~Document() = default;// 虛擬構造函數:克隆virtual Document* clone() const = 0;// 虛擬構造函數:從文件創建virtual Document* createFromFile(const std::string& filename) const = 0;// 虛擬構造函數:從數據流創建virtual Document* createFromStream(std::istream& stream) const = 0;
};class TextDocument : public Document {
public:TextDocument* clone() const override {return new TextDocument(*this);}TextDocument* createFromFile(const std::string& filename) const override {auto doc = new TextDocument();doc->loadFromFile(filename);return doc;}TextDocument* createFromStream(std::istream& stream) const override {auto doc = new TextDocument();doc->loadFromStream(stream);return doc;}
};

2.2 虛擬非成員函數技術

// 多態輸出運算符實現
class Printable {
public:virtual ~Printable() = default;virtual void print(std::ostream& os) const = 0;
};// 虛擬非成員函數:通過友元函數實現
std::ostream& operator<<(std::ostream& os, const Printable& obj) {obj.print(os);  // 多態調用return os;
}class Report : public Printable {
public:void print(std::ostream& os) const override {os << "Report Content: " << content;}private:std::string content;
};// 使用示例
void printDocument(const Printable& doc) {std::cout << doc;  // 多態調用正確的print實現
}

2.3 類型注冊與工廠模式

// 抽象工廠實現虛擬構造函數
class ShapeFactory {
public:virtual ~ShapeFactory() = default;virtual Shape* createShape() const = 0;virtual Shape* createShapeFromData(const std::vector<double>& data) const = 0;
};// 具體工廠
class CircleFactory : public ShapeFactory {
public:Circle* createShape() const override {return new Circle();}Circle* createShapeFromData(const std::vector<double>& data) const override {if (data.size() < 1) return nullptr;return new Circle(data[0]);  // 第一個數據作為半徑}
};// 工廠注冊表
class ShapeFactoryRegistry {
public:static void registerFactory(const std::string& type, ShapeFactory* factory) {getRegistry()[type] = factory;}static Shape* createShape(const std::string& type) {auto it = getRegistry().find(type);return it != getRegistry().end() ? it->second->createShape() : nullptr;}private:static std::map<std::string, ShapeFactory*>& getRegistry() {static std::map<std::string, ShapeFactory*> registry;return registry;}
};

?? 3. 解決方案與最佳實踐

3.1 完善的虛擬構造函數體系

// 綜合虛擬構造函數實現
class PolymorphicObject {
public:virtual ~PolymorphicObject() = default;// 克隆構造函數virtual PolymorphicObject* clone() const = 0;// 移動構造函數(C++11)virtual PolymorphicObject* move() = 0;// 從各種源創建virtual PolymorphicObject* createFromString(const std::string& str) const = 0;virtual PolymorphicObject* createFromStream(std::istream& is) const = 0;virtual PolymorphicObject* createFromFile(const std::string& filename) const = 0;// 序列化接口virtual std::string toString() const = 0;virtual void toStream(std::ostream& os) const = 0;
};// 具體實現
class ConfigItem : public PolymorphicObject {
public:ConfigItem* clone() const override {return new ConfigItem(*this);}ConfigItem* move() override {return new ConfigItem(std::move(*this));}ConfigItem* createFromString(const std::string& str) const override {auto item = new ConfigItem();item->parseString(str);return item;}// 其他創建方法實現...
};

3.2 虛擬非成員函數框架

// 多態比較運算符框架
class Comparable {
public:virtual ~Comparable() = default;// 虛擬比較方法virtual int compare(const Comparable& other) const = 0;// 運算符實現friend bool operator==(const Comparable& a, const Comparable& b) {return a.compare(b) == 0;}friend bool operator!=(const Comparable& a, const Comparable& b) {return a.compare(b) != 0;}friend bool operator<(const Comparable& a, const Comparable& b) {return a.compare(b) < 0;}// 其他比較運算符...
};// 具體實現
class VersionNumber : public Comparable {
public:int compare(const Comparable& other) const override {// 動態類型檢查確保類型安全const VersionNumber* otherVersion = dynamic_cast<const VersionNumber*>(&other);if (!otherVersion) {throw std::invalid_argument("Cannot compare different types");}// 實際比較邏輯if (major != otherVersion->major) return major - otherVersion->major;if (minor != otherVersion->minor) return minor - otherVersion->minor;return patch - otherVersion->patch;}private:int major, minor, patch;
};

3.3 類型安全的虛擬函數分發

// CRTP實現類型安全的虛擬操作
template<typename Derived>
class VirtualOperations {
public:// 虛擬構造函數族Derived* clone() const {return new Derived(static_cast<const Derived&>(*this));}Derived* create() const {return new Derived();}// 虛擬非成員操作friend std::ostream& operator<<(std::ostream& os, const VirtualOperations& obj) {return os << static_cast<const Derived&>(obj);}friend std::istream& operator>>(std::istream& is, VirtualOperations& obj) {return is >> static_cast<Derived&>(obj);}
};// 具體類使用
class Employee : public VirtualOperations<Employee> {
public:friend std::ostream& operator<<(std::ostream& os, const Employee& emp) {return os << "Employee: " << emp.name << ", " << emp.id;}friend std::istream& operator>>(std::istream& is, Employee& emp) {return is >> emp.name >> emp.id;}private:std::string name;int id;
};

3.4 內存安全的虛擬構造函數

// 使用智能指針的虛擬構造函數
class SafePolymorphic {
public:virtual ~SafePolymorphic() = default;// 返回智能指針的虛擬構造函數virtual std::unique_ptr<SafePolymorphic> clone() const = 0;virtual std::unique_ptr<SafePolymorphic> create() const = 0;// 工廠方法virtual std::unique_ptr<SafePolymorphic> createFrom(const std::string& data) const = 0;
};class SafeDocument : public SafePolymorphic {
public:std::unique_ptr<SafePolymorphic> clone() const override {return std::make_unique<SafeDocument>(*this);}std::unique_ptr<SafePolymorphic> create() const override {return std::make_unique<SafeDocument>();}std::unique_ptr<SafePolymorphic> createFrom(const std::string& data) const override {auto doc = std::make_unique<SafeDocument>();doc->parse(data);return doc;}
};

💡 關鍵實踐原則

  1. 優先使用智能指針
    虛擬構造函數應該返回智能指針以避免內存管理問題:

    class ModernPolymorphic {
    public:virtual ~ModernPolymorphic() = default;virtual std::unique_ptr<ModernPolymorphic> clone() const = 0;virtual std::shared_ptr<ModernPolymorphic> createShared() const = 0;
    };
    
  2. 確保類型安全
    在虛擬非成員函數中實現運行時類型檢查:

    class TypeSafeComparable {
    public:virtual bool isSameType(const TypeSafeComparable& other) const = 0;virtual int safeCompare(const TypeSafeComparable& other) const {if (!isSameType(other)) {throw std::bad_cast();}return doCompare(other);}protected:virtual int doCompare(const TypeSafeComparable& other) const = 0;
    };
    
  3. 提供完整的構造函數族
    實現一組相關的虛擬構造函數:

    class CompleteVirtualConstructor {
    public:// 基本構造virtual std::unique_ptr<CompleteVirtualConstructor> create() const = 0;// 拷貝構造virtual std::unique_ptr<CompleteVirtualConstructor> clone() const = 0;// 參數化構造virtual std::unique_ptr<CompleteVirtualConstructor> createWith(int param) const = 0;virtual std::unique_ptr<CompleteVirtualConstructor> createFrom(const std::string& data) const = 0;// 移動語義支持virtual std::unique_ptr<CompleteVirtualConstructor> move() = 0;
    };
    

虛擬構造函數設計模式

class VirtualConstructorPattern {
public:// 工廠方法模式template<typename... Args>static std::unique_ptr<VirtualConstructorPattern> create(const std::string& type, Args&&... args) {auto factory = getFactory(type);return factory ? factory->create(std::forward<Args>(args)...) : nullptr;}// 原型模式virtual std::unique_ptr<VirtualConstructorPattern> clone() const = 0;// 抽象工廠模式class Factory {public:virtual ~Factory() = default;virtual std::unique_ptr<VirtualConstructorPattern> create() const = 0;template<typename... Args>std::unique_ptr<VirtualConstructorPattern> create(Args&&... args) const {return doCreate(std::forward<Args>(args)...);}protected:virtual std::unique_ptr<VirtualConstructorPattern> doCreate() const = 0;// 可變參數模板處理template<typename... Args>std::unique_ptr<VirtualConstructorPattern> doCreate(Args&&... args) const {// 默認實現:忽略參數,調用無參版本return doCreate();}};// 注冊工廠static void registerFactory(const std::string& type, std::unique_ptr<Factory> factory) {getFactories()[type] = std::move(factory);}private:static std::map<std::string, std::unique_ptr<Factory>>& getFactories() {static std::map<std::string, std::unique_ptr<Factory>> factories;return factories;}static Factory* getFactory(const std::string& type) {auto it = getFactories().find(type);return it != getFactories().end() ? it->second.get() : nullptr;}
};

虛擬非成員函數應用

// 多態序列化框架
class Serializable {
public:virtual ~Serializable() = default;// 虛擬非成員函數:序列化friend std::ostream& operator<<(std::ostream& os, const Serializable& obj) {obj.serialize(os);return os;}// 虛擬非成員函數:反序列化friend std::istream& operator>>(std::istream& is, Serializable& obj) {obj.deserialize(is);return is;}// 虛擬非成員函數:JSON序列化friend std::string to_json(const Serializable& obj) {return obj.toJson();}// 虛擬非成員函數:從JSON創建(虛擬構造函數)static std::unique_ptr<Serializable> from_json(const std::string& json) {// 需要類型信息在JSON中return nullptr; // 實際實現需要類型注冊}protected:virtual void serialize(std::ostream& os) const = 0;virtual void deserialize(std::istream& is) = 0;virtual std::string toJson() const = 0;
};

總結
虛擬構造函數和非成員函數是強大的多態編程技術,允許在運行時動態創建對象和執行操作,大大增強了代碼的靈活性和可擴展性。

關鍵實現技術包括:原型模式(clone方法)、工廠方法模式、抽象工廠模式,以及通過友元函數實現的虛擬非成員函數。現代C++中應優先使用智能指針來管理動態創建的對象。

這些技術為構建靈活、可擴展的多態系統提供了堅實基礎,特別是在需要運行時類型創建、序列化/反序列化、多態IO操作等場景中表現出色。

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

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

相關文章

血緣元數據采集開放標準:OpenLineage Guides 在 Airflow 中使用 OpenLineage Proxy

OpenLineage 是一個用于元數據和血緣采集的開放標準&#xff0c;專為在作業運行時動態采集數據而設計。它通過統一的命名策略定義了由作業&#xff08;Job&#xff09;、運行實例&#xff08;Run&#xff09;和數據集&#xff08;Dataset&#xff09; 組成的通用模型&#xff0…

【Linux】網絡(中)

目錄1. 序列化和反序列化1.1 序列化1.2 反序列化2. 網絡版本計算器&#xff08;自定義協議&#xff09;3. 再次理解OSI七層模型4. HTTP協議4.1 HTTP協議格式4.2 HTTP的方法4.3 HTTP的狀態碼4.4 HTTP常見Header4.5 長連接和短連接4.6 Cookie5. HTTPS協議5.1 對稱加密和非對稱加密…

AI 寫作實戰:用 GPT-4o+ Claude 3 生成小紅書文案,轉化率提升 30%

引言?AI 寫作開啟小紅書營銷新引擎在社交媒體營銷的浪潮中&#xff0c;小紅書以其獨特的社區氛圍和龐大的年輕用戶群體&#xff0c;成為品牌推廣的關鍵陣地。然而&#xff0c;撰寫既吸引眼球又能高效轉化的文案并非易事&#xff0c;傳統人工編寫不僅耗時費力&#xff0c;還難以…

一個月漲粉30萬,Coze智能體一鍵生成民間傳說爆款視頻,3分鐘上手

最近發現一個賬號&#xff0c;用AI將民間傳說故事轉化為生動視頻&#xff0c;短短一個月漲粉30萬&#xff0c;條均播放 量破百萬。這種視頻制作真的需要專業團隊嗎&#xff1f;今天教大家用Coze智能體工作流&#xff0c;一鍵生成 爆款民間故事視頻&#xff01;工作流功能 用Coz…

Linux arm64 PTE contiguous bit

文章目錄一、簡介1.1 contiguous PTE1.2 demo二、Linux 內核中的實現2.1 宏定義2.2 __create_pgd_mapping2.2.1 alloc_init_cont_pmdinit_pmd2.2.2 alloc_init_cont_pteinit_pte2.3 hugetlbpage2.3.1 find_num_contig2.3.2 num_contig_ptes2.3.3 huge_pte_offset2.3.4 huge_pte…

深入分析 json2(新)與標準的 jsonrpc的區別

這兩個模塊都用于實現 JSON 風格的遠程過程調用&#xff08;RPC&#xff09;接口&#xff0c;但設計哲學、使用方式、安全性和現代化程度有顯著差異。 &#x1f4c2; 對比背景 文件 功能 來源 jsonrpc.py 標準的 JSON-RPC 2.0 兼容接口 Odoo 內核已有邏輯 json2.py 自定…

IO_HW_9_3

一、使用消息隊列實現兩個程序間的相互通信二、思維導圖三、牛客網

fastlio配置與過程中遇到的問題

&#x1f680; Fast-LIO 安裝與運行指南 我之前已經創建并使用原有的工作空間 catkin_ws,如果沒有創建一個。 使用環境 ubantu20.04 ros1 noetic版本 我作的是要在已有的 ~/catkin_ws 中編譯 原版 FAST-LIO&#xff08;來自 HKU-MARS 官方倉庫&#xff09;。 最終下載官方文檔中…

Python 工具: Windows 帶寬監控工具

Python 工具&#xff1a; Windows 帶寬監控工具環境介紹會使用的庫多線程關鍵代碼&#xff1a;系統流量采集&#xff1a;用 psutil 獲取網絡數據概念&#xff1a;網絡流量的“增量”與“總量”代碼中的流量采集邏輯Flask Web框架&#xff1a;搭建后端服務前端部分交互邏輯&…

【Java】Redis(中間件)

一、對Redis的理解Reids是一種基于內存的數據庫&#xff0c;對數據的讀寫操作都在內存中完成&#xff0c;因此讀寫速度非常快&#xff0c;常用于緩存、消息隊列、分布式鎖等場景。除此之外&#xff0c;Redis還支持事務、持久化、Lua腳本、多種集群方案&#xff08;主從復制模式…

【題解】洛谷P1776 寶物篩選 [單調隊列優化多重背包]

二進制優化還是不夠快&#xff0c;如果我們想時間復雜度為 &#xff0c;還得找新的方法。 &#xff08;W 為背包最大可承載量&#xff0c;N 為物品種類數&#xff09; 例題&#xff1a;P1776 寶物篩選 - 洛谷 原來的轉移式很普通&#xff1a; 注意到對于每個 &#xff0c;有…

數據結構_循環隊列_犧牲一個存儲空間_不犧牲額外的存儲空間 Circular Queue(C語言實現_超詳細)

目錄循環隊列的引出區別普通隊列和循環隊列兩種循環隊列的概念循環隊列深入理解題目&#xff1a;此題&#xff0c;分為犧牲一個額外空間和不犧牲一個額外空間不犧牲一個額外空間完成第一步完成第二步完成第三步完成第四步犧牲一個額外空間完成第一步完成第二步完成第三步完成第…

Linux_網絡基礎

?? 歡迎大家來到小傘的大講堂?? &#x1f388;&#x1f388;養成好習慣&#xff0c;先贊后看哦~&#x1f388;&#x1f388; 所屬專欄&#xff1a;LInux_st 小傘的主頁&#xff1a;xiaosan_blog 制作不易&#xff01;點個贊吧&#xff01;&#xff01;謝謝喵&#xff01;&a…

Portainer:Docker可視化管理神器部署與使用攻略

Portainer是一款優秀的Docker可視化管理工具&#xff0c;它提供了簡潔美觀的Web界面&#xff0c;可以通過點擊鼠標輕松管理Docker環境。 一、Portainer簡介 Portainer是一個輕量級的Docker管理界面&#xff0c;具有以下特點&#xff1a; 可視化操作&#xff1a;通過Web界面管…

OVITO3.13.1_ Mac中文_材料科學、物理及化學領域設計的數據可視化和分析軟件_安裝教程

軟件下載 【名稱】&#xff1a;****OVITO3.13.1Mac中文 【大小】&#xff1a;****154M 【語言】&#xff1a;簡體中文 【安裝環境】&#xff1a;****mac 【網站下載鏈接】&#xff1a; https://a-xing.top/3008.html軟件應用 軟件應用 Ovito能做什么&#xff1f; Ovito的功能十…

MySQL 開發避坑:DROP TABLE 前你必須知道的幾件事

MySQL 中刪除表主要使用 DROP TABLE 語句。這是一個需要非常謹慎的操作&#xff0c;因為一旦執行&#xff0c;表結構和表中的所有數據都會被永久刪除。1. 基本語法&#xff1a;刪除單個表sqlDROP TABLE [IF EXISTS] table_name;* DROP TABLE: 核心命令&#xff0c;用于刪除表…

淺談人工智能之阿里云搭建coze平臺

淺談人工智能之阿里云搭建coze平臺 一、部署環境準備 阿里云服務器配置要求 ○ 規格&#xff1a;最低2核CPU 4GB內存&#xff08;推薦4核8GB保障流暢運行&#xff09;&#xff0c;作者原先想要利舊&#xff0c;使用了2核2GB的服務器&#xff0c;但是跑不起來&#xff0c;后來自…

ego(2)---初始軌跡生成后的關鍵點采樣

在初始的多項式軌跡生成后&#xff0c;是要經過一個關鍵點采樣&#xff0c;使用關鍵點來進行后續的 B 樣條曲線擬合的。即&#xff1a;初始多項式擬合->關鍵點采樣->B樣條擬合關鍵點采樣的思路關鍵點采樣使用時間步長 ts 來在初始軌跡方程中取點。在上一步的初始軌跡生成…

專項智能練習(信息安全防護措施)

3.以下屬于網絡安全威脅的是&#xff08;A &#xff09;。 A.非授權訪問、病毒感染、信息泄露、拒絕網絡服務 B.信息泄露、非授權訪問、病毒感染、硬盤損壞 C.信息篡改、非授權訪問、病毒感染、硬盤損壞 D.網絡異常、非授權訪問、信息篡改、病毒感染 解析本題考查網絡安全威脅。…

ubuntu編譯webrtc庫

一. 前言 本文介紹在 ubuntu 下如何通過 webrtc 源碼編譯出指定版本 webrtc.lib 庫&#xff08;以 m94 版本為例&#xff09;。 二. 編譯步驟 1. 下載depot_tools工具 depot_tools 是 Google 用來管理大型項目代碼&#xff08;例如 WebRTC&#xff09;的工具集&#xff0c;它…