这篇博客参考c++任意类型Any类的实现,稍加改动。原博客中是使用泛型的占位变量Holder对象来保存数据,而Any不是模板类,Any类中构造函数是模板函数,以向Holder中存入不同类型的数据。Any类实现的主要是类型擦除这一操作,这里使用的是void*
指针,认为任何一个数据无非是存储地址与解读方式的组合,void*
指针可以保存指向任何类型数据的指针(即存储地址),剩下的再使用一个字符串类变量保存其类型(即数据的解读方式)。
该例中使用setData
函数来将Any类的对象设定为某一个具体的数据,使用getData
函数来解析Any中保存的数据,二者都是泛型函数:
class Any
{
public:
Any() :pData(NULL), type("null") {}
template<class ValueType>
Any(const ValueType& value) { setData(value); }
template<class ValueType>
void setData(const ValueType& value) { pData = (void*)(&value); type = typeid(value).name(); }
template<> void setData<Any>(const Any& value) { if (this != &value) { this->pData = value.pData; this->type = value.type; } }
template<class ValueType>
bool getData(ValueType& dst) { if (!isCompatible(dst))return false; dst = *(ValueType*)(pData); return true; }
template<class ValueType>
bool isCompatible(const ValueType& value) { return (string)(typeid(value).name()) == string(this->type); }
void* getAddress() { return pData; }
const char* getType() { return type; }
bool isNull() { return pData == NULL; }
template<class ValueType>
Any& operator=(const ValueType& value) { this->setData(value); return *this; }
template<class ValueType>
operator ValueType() { return *(ValueType*)(pData); }
template<class ValueType>
void display() { string t = (string)type; cout << "地址为:" << this << "的Any对象指向地址为:" << this->pData << "的" << this->type << "类型的数据:" << *(ValueType*)(pData) << endl; }
private:
void* pData;
const char* type;
};
其中构造函数Any(const ValueType& value)
以及=
运算符重载无非是调用了setData
,只是提供一种便利的使用方式;包括operator ValueType()
也是提供一种便利的Any类型向其他类型转换的方式;Any的display()
函数只是用于测试。其测试如下:
class Test
{
public:
int h = 4;
void display() { cout << "Test对象地址:" << this << ",h=" << h << endl; }
};
int main()
{
Any any, any1;
int a = 7, a1;
float b = 4.1, b1;
double c = 0.315, c1;
string s1 = "Hello", s2;
Test t, t1;
t.h = 5;
t1.h = 15;
any = a;
any.display<int>();
a1 = any;
cout << "a1=" << a1 << endl;
any = b;
any.display<float>();
b1 = any;
cout << "b1=" << b1 << endl;
any = c;
any.display<double>();
c1 = any;
cout << "c1=" << c1 << endl;
any = s1;
any.display<string>();
any.getData(s2);
//s2 = any;
cout << "s2=" << s2 << endl;
t.display();
any = t;
t1.display();
t1 = any;
t1.display();
any1 = any;
system("pause");
return 0;
}
可以看到Any类可以赋值为int
,float
,double
等基本类型以及string
和自定义的Test
类型,有点美中不足的是Any对象如果保存string
类型不能直接通过=
运算符赋值给string
类型变量,会出现“operatr=”不明确
错误。这个我目前不知什么原因。以下是测试结果:
建议的使用方法是:
- 给Any对象赋值:直接使用
=
运算符,如any=b
- 把Any对象赋值给其他变量:想调用
isCompatible
函数判断类型是否一样,然后使用getData
函数;对于一些基本类型的int
,float
,double
可以直接用=
运算符将Any对象赋值给其他类型,但是=
运算符方式不检查类型。
本例中方法更类似于这篇博客Any类的实现。
另外Any类在boost库中有定义,可以使用现成的轮子。