如果我有以下假设的类:
namespace System
{
template <class T>
class Container
{
public:
Container() { }
~Container() { }
}
}
如果我实例化两个具有不同 T 的容器,则说:
Container<int> a;
Container<string> b;
我想创建带有指向 a 和 b 的指针的向量。由于 a 和 b 是不同的类型,通常这是不可能的。但是,如果我做了类似的事情:
std::stack<void*> _collection;
void *p = reinterpret_cast<void*>(&a);
void *q = reinterpret_cast<void*>(&b);
_collection.push(a);
_collection.push(b);
那么稍后,我可以像这样从 _collection 返回 a 和 b:
Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());
我的问题是,这是存储不相关类型集合的最佳方法吗?这也是从向量中存储和检索指针的首选方式(重新解释转换)吗?我环顾四周,发现 boost 有一个更好的方法来解决这个问题,Boost::Any,但由于这是我正在进行的一个学习项目,我想自己做(我也很好奇找到一个很好的理由)正确使用reinterpret_cast)。
If I have the following hypothetical class:
namespace System
{
template <class T>
class Container
{
public:
Container() { }
~Container() { }
}
}
If I instantiate two Containers with different T's, say:
Container<int> a;
Container<string> b;
I would like to create vector with pointers to a and b. Since a and b are different types, normally this wouldn't be possible. However, if I did something like:
std::stack<void*> _collection;
void *p = reinterpret_cast<void*>(&a);
void *q = reinterpret_cast<void*>(&b);
_collection.push(a);
_collection.push(b);
Then later on, I can get a and b back from _collection like so:
Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());
My question is, is this the best way for storing a collection of unrelated types? Also would this be the preferred way of storing and retrieving the pointers from the vector (the reinterpret cast)? I've looked around and seen that boost has a nicer way of solving this, Boost::Any, but since this is a learning project I am on I would like to do it myself (Also I have been curious to find a good reason to use a reinterpret_cast correctly).
发布评论
评论(2)
考虑
boost::any
或boost::variant
在决定使用哪一个之前,请看一下比较:
希望它能帮助您做出正确的决定。选择一个,以及标准库中的任何容器来存储对象,
std::stack
、std::stack,或任何其他。 不要编写自己的容器。
我重复一遍不要编写自己的容器。使用标准库中的容器。它们经过充分测试。
Consider
boost::any
orboost::variant
if you want to store objects of heterogeneous types.And before deciding which one to use, have a look at the comparison:
Hopefully, it will help you to make the correct decision. Choose one, and any of the container from the standard library to store the objects,
std::stack<boost::any>
,std::stack<boost::variant>
, or any other. Don't write your own container.I repeat don't write your own container. Use containers from the standard library. They're well-tested.
虽然可以转换为
void *
并返回,但问题在于知道要弹出哪种类型。毕竟,您给出了这个例子:但是,如果您不小心这样做:
现在您已经得到了指向错误类型的指针,并且可能会看到崩溃 - 或更糟。
如果您想做这样的事情,至少使用
dynamic_cast
来检查您是否拥有正确的类型。使用dynamic_cast
,您可以在运行时进行 C++ 检查(使用 RTTI),只要被强制转换的类型(之前和之后)具有一个具有至少一个虚拟方法的公共基类型,那么您的强制转换就是安全的。因此,首先使用虚拟析构函数创建一个公共基类型:
使您的容器从中派生:
现在使用
std::stack
。当您从堆栈中检索项目时,请使用dynamic_cast; >(stack.pop())
或dynamic_cast; >(stack.pop())
;如果类型错误,它们将进行检查,并返回 NULL。也就是说,异构容器的使用几乎总是错误的。在某种程度上,您需要知道容器中的内容,以便您可以实际使用它。您实际上想通过创建这样的容器来实现什么目的?
While it is possible to cast to
void *
and back, the problem is knowing which type you're popping. After all, you give the example:However, if you were to accidentally do:
Now you've got pointers to the wrong type, and will likely see crashes - or worse.
If you want to do something like this, at least use
dynamic_cast
to check that you have the right types. Withdynamic_cast
, you can have C++ check, at runtime (using RTTI), that your cast is safe, as long as the types being casted (both before and after) have a common base type with at least one virtual method.So, first create a common base type with a virtual destructor:
Make your containers derive from it:
Now use a
std::stack<ContainerBase *>
. When you retrieve items from the stack, usedynamic_cast<Container<int> >(stack.pop())
ordynamic_cast<Container<string> >(stack.pop())
; if you have the types wrong, these will check, and will return NULL.That said, heterogeneous containers are almost always the wrong thing to be using; at some level you need to know what's in the container so you can actually use it. What are you actually trying to accomplish by creating a container like this?