简体   繁体   English

向右强制转换为void *指针

[英]Right cast for a void* pointer

I'm trying to implement a C++ class with a value field that can point to anything (a bit like in boost::any). 我正在尝试使用一个可以指向任何value字段实现C ++类(有点像boost :: any)。 Currently I do the following: 目前,我正在执行以下操作:

class MyClass {
  void* value;
  template<typename T>
  Myclass(const &T v) {
    value = (void*)(new T(v));
  }
};

The problem is now to implement a getValue() operation that creates a copy of the inner value with the right type: 现在的问题是实现一个getValue()操作,该操作创建具有正确类型的内部值的副本:

template<typename T>
T getValue() {
 return *value;
}

Here it cannot work because I'm trying to unreference a void* pointer. 在这里它不能工作,因为我试图取消引用void *指针。 I was wondering which cast (static_cast? dynamic_cast? other...) I should use such that *value is properly converted into a T object and an exception is thrown if value was not originally of this type? 我想知道应该使用哪种类型的转换(static_cast?dynamic_cast?other ...),以便将* value正确转换为T对象,并且如果value最初不是这种类型,则会引发异常?

Thanks 谢谢

You cannot dereference a void* , it simply makes no sense. 您不能取消引用void* ,这根本没有意义。 Why not make the class itself generic? 为什么不使类本身具有泛型? Then you can have: 然后您可以拥有:

template<typename T>
class MyClass {
  T* value;

  MyClass(const T& v) {
    value = new T(v);
  }

  T getValue() {
    return *value;
  }
};

Make sure to create a destructor which deallocates value and also to follow The Rule of Three . 确保创建一个析构函数,该析构函数可以分配value并遵循“三法则” You could also make a version of getValue that returns a const T& ( const reference to T ) to avoid the copy if one is not required. 您也可以创建一个getValue版本,该版本返回const T& (指向T const引用)以避免不必要的复制。

which cast (static_cast? dynamic_cast? other...) I should use such that *value is properly converted into a T object 我应该使用哪种转换(static_cast?dynamic_cast?other ...),以便将* value正确转换为T对象

If you must do this conversion, then you should use static_cast , which in general is designed to (among other things) reverse any standard conversion. 如果必须执行此转换,则应使用static_cast ,通常将其用于(除其他事项外)撤消任何标准转换。 There's a standard conversion from any object pointer type to void* , and your getter reverses it, so use the cast designed for that: 从任何对象指针类型到void*都有标准转换,您的getter会将其反转,因此请使用为此设计的强制转换:

return *static_cast<T*>(value);

You should also either remove the C-style cast from your constructor, or replace that with a static_cast too. 您还应该从构造函数中删除C样式static_cast ,或者也将其替换为static_cast

A reinterpret_cast would also work, but is "overkill". reinterpret_cast也可以,但是“过度杀伤”。 In general you should use the cast that is as restrictive as possible while still performing the conversion you need. 通常,在执行所需转换的同时,应使用尽可能严格的转换。

and an exception is thrown if value was not originally of this type 如果value最初不是此类型,则抛出异常

You are out of luck there - C++ cannot in general tell what the original type of the object was, once you've cast the pointer to void* . 您真不走运-一旦将指针转换为void* ,C ++通常就无法确定对象的原始类型是什么。 Your code relies on the caller to call getValue with the correct type. 您的代码依赖于调用方以正确的类型调用getValue For example, consider what happens if the original type was char -- that's just one byte in C++, there is no room set aside for any type information that would allow the compiler to check the cast in getValue . 例如,考虑一下如果原始类型是char ,会发生什么情况-在C ++中只有一个字节,那么就没有为任何类型信息留出空间,这将允许编译器检查getValue中的getValue

dynamic_cast does check types in some limited circumstances, but since your template is fully generic, those limited circumstances might not apply. dynamic_cast在某些有限的情况下会检查类型,但是由于您的模板是完全通用的,因此这些有限的情况可能不适用。

If you don't like this, you could change your class to store, in addition to the object pointer, a pointer to a type_info object (resulting from a use of the typeid operator). 如果您不喜欢这样做,则除了对象指针外,还可以更改类以存储指向type_info对象的指针(使用typeid运算符)。 See the standard header <typeinfo> . 参见标准标题<typeinfo> You could then compare the type_info object for the type T in the constructor, with the type_info object for the type T in getValue , and throw if they don't match. 然后,您可以比较type_info对象类型T的构造,与type_info的对象类型TgetValue ,并抛出,如果他们不匹配。

As you say, your class is intended to be a bit like boost::any , and getValue is like any_cast . 就像您说的那样,您的类打算有点像boost::any ,而getValue就像any_cast You could consult the source and documentation of that class to see the tricks needed to do what you want. 您可以查阅该类的源代码和文档,以了解完成所需的技巧。 If there were a straightforward way to do it, then boost::any would be a straightforward class! 如果有一种简单的方法,那么boost::any将是一个简单的类!

You can't. 你不能 C++ doesn't provide that sort of mechanism, at least not directly, not for void* . C ++不会(至少不是直接)提供这种机制,不是针对void* A void* does not have any information that the computer would need to determine what it is, and attempting to "check" if it is a valid whatever-you-cast-it-to is impossible because there aren't particular flags for that. void*没有任何信息表明计算机将需要确定它是什么,并且尝试“检查”它是否是有效的(随便播报)是不可能的,因为没有针对它的特定标志。

There are options, though. 虽然有选择。 The first is to use some kind of universal base class, similar to Java's Object, and derive all of your other classes from that. 首先是使用某种类似于Java的Object的通用基类,并从中派生所有其他类。 dynamic_cast will now work the way you want (returning NULL if the object is not a valid object of the class you casted it to). 现在, dynamic_cast将按照您想要的方式工作(如果对象不是将其强制转换为的类的有效对象,则返回NULL )。

Another is to simply keep track of what type of object it is yourself. 另一个是简单地跟踪您自己属于哪种类型的对象。 That means augmenting the void* with another value that tells you what you need to cast it to. 这意味着用另一个值扩展void* ,它告诉您需要将其强制转换为什么。

But really, neither of these things strike me as good ideas. 但是,实际上,这些东西都不是我的好主意。 I think there is almost-definitely some other aspect of your design that should be changed rather than using these. 我认为您的设计中几乎有其他方面应该更改而不是使用这些方面。 Using templates, as @EdS. 使用模板,如@EdS。 suggests, is a very good option, for example. 建议,例如,这是一个非常好的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM