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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;它…