【问题标题】:dynamic_cast from "void *"来自“void *”的dynamic_cast
【发布时间】:2011-05-07 01:49:32
【问题描述】:

根据thisvoid* 没有 RTTI 信息,因此从void* 进行强制转换是不合法的,这是有道理的。

如果我没记错的话,来自void*dynamic_cast 正在研究gcc。

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

【问题讨论】:

    标签: c++ rtti void-pointers dynamic-cast


    【解决方案1】:

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

    在 gcc 中你可以dynamic_cast to void* 但不能来自

    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
    }
    

    【讨论】:

      【解决方案2】:

      5.2.7 - Dynamic cast [expr.dynamic.cast] 中,它表示dynamic_cast&lt;T&gt;(v)

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

      ...

      • 否则,v 应为指向多态类型的指针或左值

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

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

      Derived1* -----> [AnotherBase] [[VDT]Base]

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

      【讨论】:

      • 如果 T 是指针类型,v 应该是指向完整类类型的指针的右值,...如果 T 是引用类型,v 应该是完整类类型的左值,...... ..
      【解决方案3】:

      确实void*不能是dynamically_casted from。

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

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

      我收到以下错误:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 除非转换为的类类型是转换自表达式的类类型的明确可访问基类,在这种情况下,后者不需要是多态的。
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 2011-10-09
            • 2014-05-29
            • 2011-03-10
            • 2014-10-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多