C++ 17 any类型的原理和简单实现

1. 什么是any类型?

C++ 17新特性,特殊的容器,可存放任意类型数据,但只能存储一个元素。

使用示例

#include <any> // 头文件
#include <iostream>
using namespace std;

// any存放内置数据类型
void test01() {
    any a = 123;

    // 用any_cast,让<<运算符知道a中存放的是什么类型数据,才可正常输出。
    cout << any_cast<int>(a) << endl;  

    a = "太强了吧";
    cout << any_cast<const char*>(a) << endl;
    
    cout << boolalpha << a.has_value() << endl; // a中有数据,输出true
    a.reset();  // 清空a,某些情况下可防止内存泄漏
    cout << boolalpha << a.has_value() << endl; // a中无数据,输出false
}

// any存放自定义数据类型
class Test {
public:
    Test(int a):mA(a) {    }
    friend ostream& operator<<(ostream& out, const Test& t); // 声明友元函数
private:
    int mA;
};

ostream& operator<<(ostream& out, const Test& t) {  // 重载<<, 在类外定义友元函数
    out << t.mA;
    return out;
}

void test02() {
    any a = Test(3);
    cout << any_cast<Test>(a) << endl; // 使用any_cast转换为Test类型再输出
    a.reset();
    system("pause");
    return 0;
}

2. any实现原理

假设我们自己实现any供用户使用,怎么实现?

思考一下:

任意类型?

→ 自然想到模板。但仅使用模板就可以吗?

template<typename T> 
class Any{
public:
    Any(T data):data_(data) { }
    }
private:
    T data_;
};

该例中使用Any类型接受任意类型时,仍需显式指定Any的类型。

场景:设计三方库供用户使用,若库中需要接受用户的返回值,但用户可能返回任意数据类型,这种简单的设计显然不行,继续思考。

any可以接收任意类型,那什么可以指向任意类型?

→ 想到了多态,基类的指针可以指向其任意派生类。

用户传来的数据怎么接收呢?

→ 因为上一条说“指向其任意派生类”,则传来的该数据应该放在派生类里。

派生类怎么存储任意类型呢?

→ 将派生类定义为类模板,在其中定义一个 data_泛型私有成员变量来存放用户传来的任意类型数据。


简单的实现方式:

class Any {
public:
    Any() = default;
    ~Any() = default;

    // Any禁止左值引用的拷贝、左值引用的赋值
    Any(const Any&) = delete;
    Any& operator=(const Any&) = delete; 

    // Any允许右值引用的拷贝、左值引用的赋值
    Any(Any&&) = default;
    Any& operator=(Any&&) = default;

    // Any的构造函数写成模板,让用户传过来的任意数据类型通过基类指针传给派生类
    template<typename T>  
    Any(T data):base_(std::make_unique<Derive<T>>(data)) { }

    // 给用户的接口:提取出Any对象中的data_数据。
    template<typename T>
    T cast_() { // cast_()函数功能: 从base_指向的Derive对象,取出data_
        // 基类指针 转为 派生类指针。需要确保该基类指针确实指向某派生类
        // get()方法为库函数,旨在获取智能指针中的裸指针
        Derive<T>* pd = dynamic_cast<Derive<T*>>(base_.get());
        if(pd == nullptr) {
            throw "cast_: 请提供正确的类型。";
        }
        return pd->data_;
    }
private:
    // 基类类型
    class Base {
    public:
        virtual ~Base() = default;
    };

    // 派生类类型,定义为模板才可以接收任意类型
    template<typename T>
    class Derive :public Base {
    public:
        Derive(T data) :data_(data) { }
        T data_;   // 存放实际接收的数据
    };
private:
    std::unique_ptr<Base> base_;  // 基类指针,可指向派生类对象
};
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的马师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值