C++ 来自“void *”的 dynamic_cast

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4131091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:36:29  来源:igfitidea点击:

dynamic_cast from "void *"

c++rttivoid-pointersdynamic-cast

提问by dimba

According to this, void*has no RTTI information, therefore casting from void*is not legal and it make sense.

根据这个void*没有RTTI信息,因此从铸造void*是不合法的,它是有意义的。

If I remember correctly, dynamic_castfrom void*was working on gcc.

如果我没记错的话,dynamic_castfromvoid*正在开发 gcc。

Can you please clarify the issue.

你能澄清一下这个问题吗?

回答by vitaut

dynamic_castworks only on polymorphic types, i.e. classes containing virtual functions.

dynamic_cast仅适用于多态类型,即包含虚函数的类。

In gcc you can dynamic_casttovoid*but not from:

在GCC可以dynamic_castvoid*,但不

struct S
{
    virtual ~S() {}
};

int main()
{
    S* p = new S();
    void* v = dynamic_cast<void*>(p);
    S* p1 = dynamic_cast<S*>(v); // gives an error
}

回答by Tony Delroy

In 5.2.7 - Dynamic cast [expr.dynamic.cast]it says that for dynamic_cast<T>(v):

5.2.7 - Dynamic cast [expr.dynamic.cast]它说dynamic_cast<T>(v)

  • If Tis a pointer type, vshall be an rvalue of a pointer to complete class type
  • If Tis a reference type, vshall be an lvalue of a complete class type (thanks usta for commenting on my missing this)
  • 如果T是指针类型,v则应是指向完整类类型的指针的右值
  • 如果T是引用类型,v则应是完整类类型的左值(感谢 usta 评论我的遗漏)

...

...

  • Otherwise, vshall be a pointer to or an lvalue of a polymorphic type
  • 否则,v应为指向多态类型的指针或左值

So, no, a (void*)valueis not allowed.

所以,不,一个(void*)是不允许的。

Let's think about what your request might mean: say you've got a pointer that's really to a Derived1*, but the code dynamic_cast-ing only knows it's a void*. Let's say you're trying to cast it to a Derived2*, where both derived classes have a common base. Superficially, you might think all the pointers would point to the same Baseobject, which would contain a pointer to the relevant virtual dispatch table and RTTI, so everything could hang together. But, consider that derived classes may have multiple base classes, and therefore the needed Baseclass sub-object might not be the one to which the Derived*- available only as a void*- is pointing. It wouldn't work. Conclusion: the compiler needs to know these types so it can perform some adjustment to the pointers based on the types involved.

让我们考虑一下您的请求可能意味着什么:假设您有一个真正指向 a 的指针Derived1*,但代码dynamic_cast只知道它是 a void*。假设您试图将其强制转换为 a Derived2*,其中两个派生类都有一个共同的基础。从表面上看,您可能认为所有的指针都指向同一个Base对象,其中包含一个指向相关虚拟调度表和 RTTI 的指针,因此一切都可以挂在一起。但是,考虑到派生类可能有多个基类,因此所需的Base类子对象可能不是Derived*- 仅作为void*- 正在指向。这行不通。结论:编译器需要知道这些类型,以便它可以根据所涉及的类型对指针进行一些调整。

Derived1* -----> [AnotherBase]
                 [[VDT]Base]    <-- but, need a pointer to start of
                 [extra members]    this sub-object for dynamic_cast

(Some answers talk about the need for the pointer you're casting from to be of a polymorphic type, having virtual functions. That's all valid, but a bit misleading. As you can see above, even if the void*is to such a type it still wouldn't work reliably without the full type information, as the real problem is that void*is presumably pointing to the start of the derived object, whereas you need a pointer to the base class sub-object from which the cast-to type derives.)

(有些答案谈到需要将您从其转换为具有虚函数的多态类型的指针。这都是有效的,但有点误导。正如您在上面看到的,即使void*是这样的类型它如果没有完整的类型信息,仍然无法可靠地工作,因为真正的问题void*可能是指向派生对象的开始,而您需要一个指向基类子对象的指针,该基类子对象是从该基类子对象派生的。 )

回答by Motti

It is true that void*can't be dynamically_casted from.

确实void*不能dynamically_cast从。

You are probably mis-remembering. With g++ 4.5 and the following code

你可能记错了。使用 g++ 4.5 和以下代码

struct A {
    virtual ~A();
};

int main() {
    A a;
    void *p = &a;
    A* pa = dynamic_cast<A*>(p);
}

I get the following error:

我收到以下错误:

cannot dynamic_cast 'p' (of type 'void*') to type 'struct A*' (source is not a pointer to class)

不能 dynamic_cast 'p'(类型为 'void*')到类型 'struct A*' (源不是指向类的指针)

回答by sharptooth

I guess you confuse with dynamic_casttovoid*. That is legal and obtains the pointer to the most derived class object.

我猜你和dynamic_castto混淆了void*。这是合法的,并获得指向最派生类对象的指针。

dynamic_castfromvoid*is illegal - the type casted from must be polymorphic - contain at least one virtual function (virtual destructor counts too).

dynamic_castfromvoid*是非法的 - 类型转换必须是多态的 - 至少包含一个虚函数(虚析构函数也算在内)。

回答by Nathan Chappell

To add to Tony's nice answer, this little code snippet helps me for some reason. First, we establish a simple hierarchy. Then, we see if dynamic_castcan "survive" a static_cast. Before this experiment I thought "the run time type information is there, dynamic cast should figure it out." Now I realize "dynamic_castmust have to look up its information based on some tables the compiler is aware of, so it can't have some magical power."

为了补充托尼的好答案,这个小代码片段出于某种原因对我有帮助。首先,我们建立一个简单的层次结构。然后,我们看看是否dynamic_cast可以“存活”一个static_cast. 在这个实验之前,我认为“运行时类型信息在那里,动态转换应该弄清楚”。现在我意识到“dynamic_cast必须根据编译器知道的一些表来查找它的信息,所以它不能有什么神奇的力量。”

#include <iostream>
#include <cassert>

using namespace std;

class A {
  protected:
  virtual void foo() { cout << "A" << endl; }
};

class B1 : public A {
  private:
  virtual void foo() override { cout << "B1" << endl; }
};

class B2 : public A {
  public:
  virtual void foo() override { cout << "B2" << endl; }
};

int main(int argc, char **argv) {
  B1 b1;
  // undefined behavior even though dynamic_cast didn't return null
  dynamic_cast<B2*>(
      static_cast<B2*>(
        static_cast<A*>(&b1)))->foo();
  // dynamic_cast returns null here though
  assert (!dynamic_cast<B2*>
          (static_cast<A*>
           (static_cast<B2*>
            (static_cast<A*>(&b1)))));
}

回答by usta

You can cast a pointer to polymorphic type to void *, but not vice versa.

您可以将指向多态类型的指针强制转换为void *,但反之则不行。