我正在设计一个简单的Array
类,它具有保存任何类型对象的能力,就像一个可以在一个对象中保存多种类型数据的向量。 (这是出于学习目的。)
我有一个名为Container
的空基类:
class Container {};
一个名为Object
的模板化子类:
template <class T>
class Object : public Container {
T& object;
public:
Object(T& obj = nullptr) : object(obj) {}
};
我有一个Array
类,其中包含vector
指向Container
的指针,用于保存Object
s:
class Array {
std::vector<Container *> vec;
public:
template <class T>
void add_element(const T&);
auto get_element(int);
};
add_element
将元素存储到Object
中并将其放入vec
:
template <class T>
void Array::add_element(const T& element)
{
vec.push_back(new Object<T>(element));
}
get_element
从Object
中移除元素并将其传递回调用者。这就是我的问题所在。要从Object
中删除元素,我需要知道它是Object
的类型:
auto Array::get_element(int i)
{
return (Object</* ??? */> *)vec[i])->object;
}
我有什么方法可以找出我正在存储的对象吗?
编辑:因为人们声称这是不可能的,所以这个怎么样。有没有办法在类中存储类型信息? (我知道你可以用红宝石做到这一点)。如果我能做到这一点,我可以在每个get_element
中存储Object
的返回类型。
答案 0 :(得分:2)
我正在考虑为您的get_element
创建此模板的内容。
template <class T>
T& Array::get_element(int i, T &t)
{
Object<T> *o = dynamic_cast<Object<T> *>(vec[i]);
if (o == 0) throw std::invalid_argument;
return t = o->object;
}
Array arr;
double f;
int c;
arr.get_element(0, f);
arr.get_element(1, c);
但另外,你可以使用它:
template <class T>
T& Array::get_element(int i)
{
Object<T> *o = dynamic_cast<Object<T> *>(vec[i]);
if (o == 0) throw std::invalid_argument;
return o->object;
}
f = arr.get_element<double>(0);
c = arr.get_element<int>(1);
答案 1 :(得分:1)
必须在编译时确定像Array::get_element
这样的函数的返回类型。由于类Array
不知道它在编译时存储的容器类型,唯一的选择是只返回基本Container*
指针。然后,该代码的用户可以使用虚函数和/或dynamic_cast
来处理这些通用容器。
答案 2 :(得分:1)
dynamic_cast&lt;&gt;(),当在指针上使用时,可用于检查强制转换是否实际可行,因为当类型不匹配时它返回NULL。
但是,您可能想重新考虑您的设置;如果你可以避免使用dynamic_cast,那么你可以使用dynamic_cast,并且如果object-is-type1那么执行此操作;否则如果object-is-type2则执行此操作;否则如果object-is-type3 ......“几乎总是设计糟糕的明显标志。
在你的get_element中使用auto可能是解决问题的一个技巧,你不知道它将是什么类型 - 但这不起作用。编译器仍然必须知道返回类型;它不能在运行时改变。
编辑:您可能还会退后一步,问自己是否真的需要一个可以存储“任何东西”的数组。我已经使用了Objective-C很长一段时间了,它基本上围绕着这样的想法:一切都只是一个“对象”,人们可以在任何事情上调用任何东西,它们都在运行时整理出来。但是,我发现实际使用这种情况很少见......特别是对于容器,我发现我使用的每个NSArray只有一种类型的对象,或者可能是一个共同的基类,但实际上并不是不同的,不相关的类