手写 C++ Any 类:深入理解多态与模板(示例详解)

 更新时间:2026年05月28日 10:39:25   作者:WWTYYDS_666  
这段代码详细介绍了使用C++实现类型擦除的类Placeholder,通过抽象基类和模板子类实现类型安全的存储与操作,强调了RAII机制和拷贝交换法在内存管理中的关键作用,感兴趣的朋友一起看看吧

我们自己实现的阉割版 Any 类核心能力:用一个类存储任意类型数据(int/自定义类/字符串等),底层依靠 抽象基类+模板子类 实现类型擦除。

模块1:头文件包含

#include <iostream>   // 输入输出
#include <typeinfo>   // 类型识别:typeid 运算符核心依赖
#include <utility>    // 标准库 swap 函数
#include <cassert>    // 断言:类型不匹配时报错

讲解

这四个头文件是实现 Any 类的基础:

  • typeinfo:提供 typeid,用于类型安全校验;
  • utility:提供 std::swap,实现高效交换;
  • cassert:断言,防止非法类型获取数据,保证程序安全。

模块2:内部抽象基类holder(类型擦除核心接口)

class holder
{
public:
    virtual ~holder(){}  // 虚析构函数
    virtual const std::type_info& type() =0; // 纯虚函数:获取类型
    virtual holder* clone()=0; // 纯虚函数:克隆对象
};

讲解

  1. 定位:Any 类的私有内部抽象类,对外完全隐藏;
  2. 虚析构:必须加!保证多态删除子类对象时,析构函数能被正确调用,防止内存泄漏;
  3. 纯虚函数:
    • type():返回存储数据的类型信息;
    • clone():深拷贝对象,支持 Any 的拷贝/赋值;
  4. 作用:定义统一接口,屏蔽具体类型差异,是类型擦除的基石。

模块3:模板子类placeholder<T>(真正存储数据的地方)

template<class T>
class placeholder:public holder
{
public:
    placeholder(const T&val):_val(val){}
    virtual const std::type_info& type(){return typeid(T);}
    virtual holder* clone(){return new placeholder(_val);}
public:
    T _val; // 真实存储数据的变量
};

讲解

  1. 模板类:T 是任意类型(int/Test/string…),真正实现存储任意数据;
  2. 继承 holder:满足多态要求,对外统一表现为 holder 类型;
  3. 构造函数:初始化成员变量 _val,存入数据;
  4. 重写纯虚函数:
    • type():返回当前模板类型 T 的信息;
    • clone():创建自身副本,实现深拷贝;
  5. 核心:_val 是真实数据存储位置,外部完全不可见。

模块4:Any类核心成员 + 构造/析构函数

holder*_content; // 核心指针
// 默认构造:空对象
Any():_content(nullptr){}
// 模板构造函数:接收任意类型数据
template<class T>
Any(const T&val):_content(new placeholder<T>(val)){}
// 拷贝构造函数:深拷贝
Any(const Any&other):_content(other._content?other._content->clone():nullptr)
{}
// 析构函数:自动释放内存
~Any(){delete _content;}

讲解

  1. 核心成员 _content:
    holder 基类指针,多态指向 placeholder<T> 子类对象,实现类型擦除;
  2. 默认构造:创建空的 Any 对象;
  3. 模板构造:接收任意类型 T,创建 placeholder<T> 对象并赋值给指针;
  4. 拷贝构造:调用 clone() 实现深拷贝,避免浅拷贝指针悬空;
  5. 析构函数:RAII 机制,自动释放内存,无需手动管理指针。

模块5:交换函数swap(异常安全核心)

Any&swap(Any&other)
{
    std::swap(_content,other._content);
    return *this;
}

讲解

  1. 作用:避免自赋值,先构造一个临时对象,再交换交换两个 Any 对象的内部指针;
  2. 价值:是拷贝交换法的基础,让赋值运算符异常安全、无内存泄漏、无需处理自赋值;
  3. 极简高效:仅交换指针,不拷贝数据,性能极高。

模块6:数据获取函数get<T>()(类型安全)

template<class T>
T*get()
{
    assert(typeid(T)==_content->type());
    return &((placeholder<T>*)_content)->_val;
}

讲解

  1. 模板函数:指定要获取的类型 T;
  2. 断言校验:类型不匹配直接终止程序,保证类型安全;
  3. 类型强转:将基类指针强转为子类指针,获取真实数据 _val;
  4. 返回值:返回数据指针,可读写内部数据。

模块7:赋值运算符重载(两种赋值方式)

// 赋值1:任意类型直接赋值给 Any
template<class T>
Any& operator=(const T&val)
{
    Any(val).swap(*this);
    return *this;
}
// 赋值2:Any 对象之间赋值
Any& operator=(const Any&other)
{
    Any(other).swap(*this);
    return *this;
}

讲解

  1. 统一用法:拷贝交换法,C++ 赋值运算符最优写法;
  2. 原理:
    ① 先创建临时对象 Any(val) / Any(other);
    ② 交换临时对象和当前对象的指针;
    ③ 临时对象析构,自动释放旧内存;
  3. 优点:避免自赋值问题,异常安全, 无内存泄漏,代码极简

模块8:测试类Test(验证生命周期)

class Test
{
public:
    Test(){ std::cout<<"构造"<<std::endl;}
    Test(const Test&t){ std::cout<<"拷贝构造"<<std::endl;}
    ~Test(){ std::cout<<"析构"<<std::endl;}
};

讲解

自定义测试类,通过打印构造/拷贝构造/析构日志,验证:

  1. Any 类能正常存储自定义类型;
  2. 内存管理正确,无泄漏;
  3. 拷贝/赋值行为符合预期。

模块9:主函数测试(功能验证)

int main()
{
    Any a;
    {
        Test t;
        a=t;
    }
    a=10;
    int *pa=a.get<int>();
    std::cout<<*pa<<std::endl;
    return 0;
}

讲解

  1. 测试空对象初始化;
  2. 测试自定义类型赋值;
  3. 测试局部对象生命周期;
  4. 测试int 类型赋值 + 获取数据;
  5. 验证全程内存自动管理,无泄漏。

核心总结

  1. holder:抽象接口,定义统一规范;
  2. placeholder:模板子类,真正存数据;
  3. _content:基类指针,多态+类型擦除核心;
  4. 拷贝交换法:赋值运算符最优解;
  5. RAII:构造申请内存,析构自动释放。

到此这篇关于手写 C++ Any 类:深入理解多态与模板(示例详解)的文章就介绍到这了,更多相关 C++ Any 类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vs2019安装及简单处理技巧(超详细)

    vs2019安装及简单处理技巧(超详细)

    这篇文章主要介绍了vs2019安装及简单处理方法,本文是一篇非常详细的教程,通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • C++任意线程通过hwnd实现将操作发送到UI线程执行

    C++任意线程通过hwnd实现将操作发送到UI线程执行

    做Windows界面开发时,经常需要在多线程环境中将操作抛到主线程执行,下面我们就来学习一下如何在不需要重新定义消息以及接收消息的情况下实现这一要求,感兴趣的可以了解下
    2024-03-03
  • C++ 检测文件大小和文件传输的方法示例详解

    C++ 检测文件大小和文件传输的方法示例详解

    文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解压逻辑,同时提供代码模板生成建议,支持跨平台及多种传输协议(如USB/Socket)的集成方案,感兴趣的朋友一起看看吧
    2025-06-06
  • 简单说说STL的内存管理

    简单说说STL的内存管理

    <STL 源码剖析>将其描述为空间配置器,理由是allocator可以将其它存储介质(例如硬盘)做为stl 容器的存储空间。由于内存是allocator管理的主要部分,因此,本文以STL内存管理为出发点介绍allocator
    2013-09-09
  • c++中的字节序与符号位的问题

    c++中的字节序与符号位的问题

    这篇文章主要介绍了c++中的字节序与符号位的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C语言实现简单翻译功能

    C语言实现简单翻译功能

    这篇文章主要为大家详细介绍了C语言实现简单翻译功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • C++多态特性之派生与虚函数与模板详细介绍

    C++多态特性之派生与虚函数与模板详细介绍

    这篇文章主要介绍了C++多态的特性派生与虚函数与模板,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-09-09
  • Qt5.14.2使用虚拟键盘的关键代码

    Qt5.14.2使用虚拟键盘的关键代码

    对于Qwidget程序,使用qtvirtualkeyboard弹出键盘之后,键盘会浮于表面。使用VirtualkeyboardPushView模块,自动根据情况把输入视图往上面推移,这篇文章主要介绍了Qt5.14.2使用虚拟键盘的关键代码,需要的朋友可以参考下
    2022-09-09
  • C语言入门篇--四大常量(字面,const修饰,宏,枚举)及标识符

    C语言入门篇--四大常量(字面,const修饰,宏,枚举)及标识符

    本篇文章是c语言基础篇,主要讲述一下常量,常量即不可被直接修改的量(const修饰的常变量可间接修改,后续文章会继续说明)请大家持续关注脚本之家
    2021-08-08
  • 简单介绍C++中变量的引用

    简单介绍C++中变量的引用

    这篇文章主要简单介绍了C++中变量的引用,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09

最新评论