我正在尝试实现一个带有value
字段的C ++类,它可以指向任何东西(有点像boost :: any)。目前我做以下事情:
class MyClass {
void* value;
template<typename T>
Myclass(const &T v) {
value = (void*)(new T(v));
}
};
现在的问题是实现一个getValue()操作,该操作使用正确的类型创建内部值的副本:
template<typename T>
T getValue() {
return *value;
}
这里它无法工作,因为我试图取消引用void *指针。我想知道哪个强制转换(static_cast?dynamic_cast?其他...)我应该使用*值正确转换为T对象,如果值最初不是这种类型,则抛出异常?
由于
答案 0 :(得分:4)
你无法取消引用void*
,这根本没有意义。为什么不让这个类本身通用?然后你可以:
template<typename T>
class MyClass {
T* value;
MyClass(const T& v) {
value = new T(v);
}
T getValue() {
return *value;
}
};
确保创建一个析构函数,该析构函数释放value
并关注The Rule of Three。您还可以制作getValue
版本,该版本会返回const T&
(const
对T
的引用)以避免副本(如果不需要)。
答案 1 :(得分:1)
哪个cast(static_cast?dynamic_cast?其他...)我应该使用*值正确转换为T对象
如果你必须进行这种转换,那么你应该使用static_cast
,它通常用于(除其他外)反向任何标准转换。从任何对象指针类型到void*
的标准转换,你的getter将其反转,所以使用为此设计的演员:
return *static_cast<T*>(value);
您还应该从构造函数中删除C样式的强制转换,或者用static_cast
替换它。
reinterpret_cast
也可行,但“过度杀伤”。通常,您应该使用尽可能限制的强制转换,同时仍然执行所需的转换。
如果value最初不属于此类型,则抛出异常
你运气不好 - 一旦你将指针转换为void*
,C ++通常无法告诉对象的原始类型是什么。您的代码依赖于调用者以正确的类型调用getValue
。例如,考虑如果原始类型为char
会发生什么 - 这只是C ++中的一个字节,没有任何空间可用于允许编译器检查getValue
中的强制转换的任何类型信息
dynamic_cast
会在某些有限的情况下检查类型,但由于您的模板完全是通用的,因此这些有限的情况可能不适用。
如果您不喜欢这样,除了对象指针之外,您可以更改要存储的类,指向type_info
对象的指针(使用typeid
运算符产生) 。请参阅标准标题<typeinfo>
。然后,您可以将构造函数中类型type_info
的{{1}}对象与T
中类型type_info
的{{1}}对象进行比较,如果它们为throw,则抛出不匹配。
正如您所说,您的课程有点像T
,getValue
就像boost::any
。您可以查阅该类的源代码和文档,以查看执行所需操作所需的技巧。如果有一种直截了当的方法,那么getValue
将是一个简单的课程!
答案 2 :(得分:0)
你做不到。 C ++不提供这种机制,至少不是直接提供,不适用于void*
。 void*
没有任何信息,计算机需要这些信息来确定它是什么,并试图“检查”它是否是有效的,无论你是什么,它是什么?不可能,因为没有特别的标志。
但也有选择。第一种是使用某种通用基类,类似于Java的Object,并从中派生出所有其他类。 dynamic_cast
现在将以您希望的方式工作(如果对象不是您将其转换为的类的有效对象,则返回NULL
。)
另一个是简单地跟踪它自己的对象类型。这意味着使用另一个值来增加void*
,告诉您需要将其投射到什么位置。
但实际上,这些事情都不能成为好主意。我认为你的设计中几乎肯定会有一些其他方面需要改变而不是使用它们。使用模板,如@EdS。建议,例如,这是一个非常好的选择。