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_; // 基类指针,可指向派生类对象
};