来自“void *”的dynamic_cast

发布于 2024-10-01 11:04:42 字数 289 浏览 7 评论 0原文

根据 thisvoid* 有没有 RTTI 信息,因此从 void* 进行转换是不合法的,但它是有意义的。

如果我没记错的话,来自 void*dynamic_cast 正在 gcc 上运行。

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

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

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

Can you please clarify the issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

花开浅夏 2024-10-08 11:04:42

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

在 gcc 中,您可以 dynamic_cast to void* 但不能 from

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
}

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

In gcc you can dynamic_cast to void* but not from:

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
}
罗罗贝儿 2024-10-08 11:04:42

5.2.7 - 动态转换 [expr.dynamic.cast] 中,它表示对于 dynamic_cast(v)

  • 如果 T 是指针类型,v 应是指向完整类类型的指针的右值
  • 如果 T 是引用类型,v 应是以下的左值一个完整的类类型(感谢usta对我遗漏的评论)

...

  • 否则,v应该是一个指向多态类型的指针或多态类型的左值

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

让我们考虑一下您的请求可能意味着什么:假设您有一个真正指向 Derived1* 的指针,但代码 dynamic_cast-ing 只知道它是一个 无效*。假设您尝试将其转换为 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

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

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

  • If T is a pointer type, v shall be an rvalue of a pointer to complete class type
  • If T is a reference type, v shall be an lvalue of a complete class type (thanks usta for commenting on my missing this)

...

  • Otherwise, v shall be a pointer to or an lvalue of a polymorphic type

So, no, a (void*) value is not allowed.

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 Base object, 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 Base class 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.

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.)

是伱的 2024-10-08 11:04:42

确实,不能对 void* 进行 dynamically_cast 编辑。

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

struct A {
    virtual ~A();
};

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

我收到以下错误:

无法将“p”(类型为“void*”)动态转换为类型“struct A*”(源不是指向类的指针)

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

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

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)

虐人心 2024-10-08 11:04:42

为了补充托尼的好答案,这个小代码片段出于某种原因对我有帮助。首先,我们建立一个简单的层次结构。然后,我们看看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)))));
}

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_cast can "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_cast must have to look up its information based on some tables the compiler is aware of, so it can't have some magical power."

#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)))));
}
深巷少女 2024-10-08 11:04:42

我猜您与 dynamic_cast to void* 混淆了。这是合法的,并且获得指向最派生类对象的指针。

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

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

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

烙印 2024-10-08 11:04:42

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文