C++ any类的设计

本文探讨了C++17中any类如何实现动态数据类型的存储,通过虚基类和模板派生类的方式,使得非模板类any能保存各种类型的对象。any类内部使用一个基类指针指向模板派生类的实例,以此达到泛化存储的目的,同时保证了类型安全。文章还对比了C++中的template、void*和union在处理任意类型数据时的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在JAVA中,有Object类,是所有类的基类,在很多时候,为了设计出通用的程序,需要将Object类作为函数参数或者返回类型(这样可以指向任何数据对象)。在C++17中,也出现了这样一个类,即 any 类。

any a(10);
any b("abandon");
//不是下面这种
any<int> a(10);
any<std::string> b("abandon");

如果用了模版参数变成 any<int> any_value(10) 这样,那 any_value 就确定是 int 类型,并且在使用时还需要传类型作为模版参数。所以,any 必须不能是模板类。那么问题来了,如果 any 不是模板类,它怎么才能泛化的保存各种类型呢?答案就在 虚基类和它的派生模板类

因为any不是模板类不能保存泛型数据,那就需要将原数据用一种容器包起来,然后让any持有一个指针,指向这个容器。那么很明显,这个容器类必须是模板类,因为这样它才能保存泛型数据,而又因为any不是模板类,它的任何数据成员都不能是泛型的,那就需要一个基类,让any持有这个基类的指针,而“容器”从这个基类派生并带模版参数。这样就解决了问题,即让原来需要泛型化存储数据的的any不泛型化,转而定义一种泛型化容器来保存数据,而any自己握住该泛型化容器基类的指针指向这个泛型化的容器。太绕了...绕这么一圈的目的,就是为了开始提到的涉及初衷:提供一种动态的数据类型,并接受单个对象的同时能够获得它的类型。

// Any类型:可以接收任意数据的类型
class Any
{
public:
	Any() = default;
	~Any() = default;
	Any(const Any&) = delete;
	Any& operator=(const Any&) = delete;
	Any(Any&&) = default;
	Any& operator=(Any&&) = default;

	// 这个构造函数可以让Any类型接收任意其它的数据
	template<typename T>  // T:int    Derive<int>
	Any(T data) : base_(std::make_unique<Derive<T>>(data))
	{}

	// 这个方法能把Any对象里面存储的data数据提取出来
	template<typename T>
	T cast_()
	{
		// 我们怎么从base_找到它所指向的Derive对象,从它里面取出data成员变量
		// 基类指针 =》 派生类指针   RTTI
		Derive<T>* pd = dynamic_cast<Derive<T>*>(base_.get());
		if (pd == nullptr)
		{
			throw "type is unmatch!";
		}
		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_;
};

思考一个问题:

C++中任意类型的数据,可以用哪些方法? template、void*、union结构体

union结构体,只能存放固定种类的值,没有扩展性

void* :C++是强类型语言,用void* 保存后丢失了类型的信息,很难保证类型安全。(什么是类型安全?类型安全很大程度是可以等价为内存安全,类型安全的代码不会去访问自己没有授权的内存区域,类型安全是指同一段内存在不同的地方,会被强制要求使用相同的办法来解释(内存中的数据是用类型来解释的))Java语言是类型安全的,除非强制类型转换。C语言不是类型安全的,因为同一段内存可以用不同的数据类型来解释,比如1用int来解释就是1,用boolean来解释就是true。

	int a = 10;
	void* p = &a;
	double* dp = (double*)p;
	cout << *dp << endl;

输出:-9.25596e+61

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值