这几天,在设计任意类型的数据存储、管理类时,被一个问题卡住了很久,即如何设计一个类,任意类型可以转化到它,并且它也可以根据需要转回去呢?
后者好说,前者猛地一看,这不用template就搞定了吗,然而,并没有这么简单。比如我们用类模板T作用于我们的类,假设叫Data,任意类型的数据存在变量data中:
template <class T>
class Data {
public:
...
private:
T data;
};
但是,这样做,Data类在实例化对象时,需要提供类型:
Data<int> d(123);
若Data被另一个类Manager引用,并把Data的实例化对象存在其成员变量里:
class Manager {
public:
...
private:
vector<Mdata<int>> buffer;
};
这样做只能把Mdata<int>的数据存储,即在声明时就锁死了它的类型,可我们并不想这样,因为类型是不确定的,甚至动态调整的。并且想通过一个Manager就可以管理任何类型。
如果把Manager也被template作用:
template <class T>
class Manager {
public:
...
private:
vector<data<T>> buffer;
};
这样Manager实例化一个对象也需要显示声明类型,并且buffer的Mdata也会变成这个相同的类型,但是我们想要实现一个多类型的Manager,那么将template作用于变量不就可以了?
class Manager {
public:
...
private:
template <class T>
vector<Data<T>> buffer;
};
然而,此时编辑器会报错:
成员 "Manager::buffer" 不是有效的类成员模板C/C++(786)
<error-type> Manager::buffer
即template是不能作用于成员变量的,但是成员函数和类等可以。[虚函数也不可以]
那么在Data的设计时,就不能设计成模板类,然而数据怎么存呢?
我们可以用万能指针void *保存:
class Data {
public:
...
private:
void * ptr{nullptr};
};
然后将,模板类作用于构造函数即可(或者其他传数据的函数)
class Data {
public:
template <class T>
Data(T data){
}
private:
void * ptr{nullptr};
};
在传入data后,可以直接ptr指向data:
class Data {
public:
template <class T>
Data(T data){
ptr = &data;
}
private:
void * ptr{nullptr};
};
第一个问题,即存储解决了,那如何变回来呢?
直接强制类型转换指针类型,然后取地址即可。
class Data {
public:
template <class T>
Data(T data){
ptr = &data;
}
template <class T>
T transferToOriginalData()
{
T *res_ptr{(T *)ptr};
return *res_ptr;
}
private:
void * ptr{nullptr};
};
样例:
string str = “1234”;
Data d(str);
auto res = d.tansforToOriginData<string>();
cout<<res;
这样,通过输入字符串str存储d中,然后调用模板类作用的函数,声明它的类型,就能得到存储的字符串了,同时,Manager也不需要考虑变量的模板类问题。
class Manager {
public:
...
private:
vector<Data> buffer;
};