接上一主题,C++14中如何设计类似于std::any,使集合在C++中与Python一样支持任意数据?
这篇文章的重点是C++多态的应用,但是如果你是C++新手,
你需要了解以下C++知识:
类
构造函数
拷贝构造函数
虚拟函数
纯虚拟函数
析构函数
类的继承
运算符重写
模板类
模板参数
数组
数组的传递
指针与动态内存分配
Python:
s = { 3,3,5,9 ,3.14,"神主级","九阳天怒","python"};
print(s)
C++:
std::list<int> li = { 1,3,4,5,6,7,8,9 };
std::vector<_any> li_any = { "焚心妖莲",1,2,15, _t("逆天邪神"),li ,3.14 };
上面一行代码中,有 char Array[], int, wchar_t Array[], 链表, Dobule
下面我们设计一个类 _any,它在构造函数如果是这样,上面语句就能编译过关。
class _any {
public:
template<class T>
_any(const T& tValue) {
}
};
int main() {
std::list<int> li = { 1,3,4,5,6,7,8,9 };
std::vector<_any> li_any = { "焚心妖莲",1,2,15, _t("逆天邪神"),li ,3.14 };
}
上面最难的地方是在类_any内部中如何保存 tValue的值,如果把类声明为模板类,很容易解决,但是就要在每_any指定模板参数T,这样行不行?
用: std::shared_ptr吗?
auto s = std::make_shared<T>(tValue);
也不行,变量声明也要带T的参数。
那应该怎么办了,查了一个资料,最后就是用C++的多态?
多态是C++中的一个核心概念,它允许基类的指针或引用调用派生类中定义的方法。多态性通过函数重写和函数重载提供。
看下面代码,你明白了吗?
上在代码还存在一个问题?
上面 “焚心妖莲” 传递的是数组 T = char Array[] 和 T = wchar_t Array[],没关系,改一下就行,在_any再加
个构造函数?
/// <summary>
/// 传递的是数组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="n"></typeparam>
/// <param name="arr"></param>
/// 创建时间: 2024-11-23 最后一次修改时间:2024-11-23
template<typename T, std::size_t n>
_any(T(&arr)[n]) : _pData(new _AnyHelper<std::decay_t<T>>(arr,n))
{
}
下面给出完整的代码,这代码也是初步的,还有很多要修改之处:
_any.h
/******************************************************************
文件名 : _any.h
作者 : 李锋
功能 : std::any
手机 : 13828778863
Email : ruizhilf@139.com
创建时间 : 2024年11月23日
最后一次修改时间 : 2024年11月23日
https://baike.baidu.com/item/deque/849385?fr=ge_ala
******************************************************************/
#pragma once
///
#include "__std_in.h"
using lf::m;
///
__STD_BEGIN_
///
/*
感谢作者:
参考: C++ std::any的模拟实现 https://blog.csdn.net/qq_54121864/article/details/136005240
class Any
{
private:
class AnyHelperBase
{
public:
virtual const std::type_info& Type()const = 0;
virtual AnyHelperBase* Clone()const = 0;
};
template<typename T>
class AnyHelper :public AnyHelperBase
{
public:
T data;
template<typename ...Args>
AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}
AnyHelper(const AnyHelper& other) :data(other.data) {}
AnyHelper(const T& value) :data(value) {}
virtual const std::type_info& Type()const
{
return typeid(T);
}
virtual AnyHelper* Clone()const
{
return new AnyHelper(*this);
}
};
template<typename T>
friend T AnyCast(const Any& any);
template<typename T>
friend T AnyCast(Any& any);
template<typename T>
friend T AnyCast(Any&& any);
template<typename T>
friend const T* AnyCast(const Any* any);
template<typename T>
friend T* AnyCast(Any* any);
AnyHelperBase* data;
public:
Any() :data(nullptr) {}
template<typename T>
Any(const T& value) : data(new AnyHelper<std::decay_t<T>>(value)) {}
Any(const Any& other) :data(other.data->Clone()) {}
Any(Any&& other) :data(other.data)
{
other.data = nullptr;
}
const std::type_info& Type()const
{
return data->Type();
}
bool HasValue()const
{
return data != nullptr;
}
void Reset()
{
if (data != nullptr)
delete data;
data = nullptr;
}
template<typename T>
Any& operator=(const T& value)
{
if (data != nullptr)
delete data;
data = new AnyHelper<std::decay_t<T>>(value);
return *this;
}
Any& operator=(const Any& other)
{
if (data != nullptr)
delete data;
data = other.data->Clone();
return *this;
}
Any& operator=(Any&& other)
{
if (data != nullptr)
delete data;
data = other.data;
other.data = nullptr;
return *this;
}
void Swap(Any& other)
{
AnyHelperBase* temp = this->data;
this->data = other.data;
other.data = temp;
}
template<typename T, typename ...Args>
std::decay_t<T>& Emplace(Args&&... args)
{
if (data != nullptr)
delete data;
auto temp = new AnyHelper<std::decay_t<T>>(std::forward<Args>(args)...);
data = temp;
return temp->data;
}
~Any()
{
if (data != nullptr)
delete data;
}
};
template<typename T>
T AnyCast(const Any& any)
{
auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
if (p == nullptr)
throw std::runtime_error("Bad any cast!");
return p->data;
}
template<typename T>
T AnyCast(Any& any)
{
auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
if (p == nullptr)
throw std::runtime_error("Bad any cast!");
return p->data;
}
template<typename T>
T AnyCast(Any&& any)
{
auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any.data);
if (p == nullptr)
throw std::runtime_error("Bad any cast!");
return p->data;
}
template<typename T>
const T* AnyCast(const Any* any)
{
auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
if (p == nullptr)
return nullptr;
return &p->data;
}
template<typename T>
T* AnyCast(Any* any)
{
auto p = dynamic_cast<Any::AnyHelper<std::decay_t<T>>*>(any->data);
if (p == nullptr)
return nullptr;
return &p->data;
}
*/
///
class _any {
public:
class _AnyHelperBase
{
public:
virtual const std::type_info& Type()const = 0; // { return typeid(nullptr); }
virtual _AnyHelperBase* Clone() const = 0; //{ return nullptr; }
virtual bool Equal(const _any& r)const = 0; // { return false; }
virtual void* GetDataPointer()const = 0; // return null; }
};
template<typename T>
class _AnyHelper :public _AnyHelperBase
{
public:
/// <summary>
/// 用数组来保存T类型数据,如果是单个T类型数据,数据就是 _data[0],
/// 否则是 _data.GetDataPointer(),如字符串。
/// </summary>
lf::_Array<T> _data;
public: //-------------------------------构造
_AnyHelper(const T* pt, const size_t& nCount) {
_data.SetBuffer(nCount + 1);
_data.Add(pt, nCount);
_data.ZeroBufferAll();
}
/// <summary>
/// 拷贝构造
/// </summary>
/// <param name="r"></param>
_AnyHelper(const _AnyHelper& r) {
_data = r._data;
}
public: //-----------------------------------重写
virtual const std::type_info& Type()const override
{
return typeid(T);
}
/// <summary>
/// 返回一个新的对象指针
/// </summary>
/// <returns></returns>
virtual _AnyHelper* Clone()const override
{
return new _AnyHelper(*this);
}
/// <summary>
/// 原则:
/// 相同数据才判断是否相等
///
/// </summary>
/// <param name="r"></param>
/// <returns></returns>
/// 创建时间: 2024-11-23 最后一次修改时间:2024-11-23
virtual bool Equal(const _any& r)const override{
if (Type() == r._pData->Type()) {
return _data == ((_AnyHelper<T>*)r._pData)->_data;
}
return false;
}
virtual void* GetDataPointer()const override {
if (_data.size() == 0)
return nullptr;
else if (_data.size() == 1)
return &_data[0];
else
return _data.DataPointer();
}
public: //-----------------------------------------运算符重载
};
public: //-------------------------------------------------_any
_AnyHelperBase* _pData;
public:
_any() :_pData(nullptr) {};
/// <summary>
/// 传递的是数组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="n"></typeparam>
/// <param name="arr"></param>
/// 创建时间: 2024-11-23 最后一次修改时间:2024-11-23
template<typename T, std::size_t n>
_any(T(&arr)[n]) : _pData(new _AnyHelper<std::decay_t<T>>(arr,n))
{
}
template<class T>
_any(const T& tValue) :_pData(new _AnyHelper<std::decay_t<T>>(&tValue,1)) {
}
_any(const _any& other) : _pData(other._pData->Clone()) {
}
~_any() {
if (_pData != 0)
delete _pData;
}
//-------------------------------------运算符重载
bool operator==(const _any& r)const {
return _pData->Equal(r);
}
void* GetDataPointer()const {
return _pData->GetDataPointer();
}
template<class T>
const T& ConvertTo() const {
const T* pt = (T*)_pData->GetDataPointer();
return *pt;
}
};
///
///
__STD_END_
///
下面是例子:
int main() {
std::list<int> li = { 1,3,4,5,6,7,8,9 };
std::vector<_any> li_any = { "焚心妖莲",1,2,15, _t("逆天邪神"),li ,3.14 };
_any ali = li;
auto li2 = ali.ConvertTo<std::list<int>>();
_pn(li2);
auto f = std::find(li_any.begin(), li_any.end(), li);
if (f != li_any.end())
std::cout << (*f)._pData->Type().name() << "\n";
f = std::find(li_any.begin(), li_any.end(), 3.14);
if (f != li_any.end())
std::cout << (*f)._pData->Type().name() << "\n";
return 0;
}