【问题标题】:static_cast from Derived* to void* to Base*static_cast 从 Derived* 到 void* 到 Base*
【发布时间】:2013-10-27 03:31:12
【问题描述】:

我想将指向派生类成员的指针转换为 void* 并从那里转换为基类的指针,如下例所示:

#include <iostream>

class Base
{
    public:
       void function1(){std::cout<<"1"<<std::endl;}
       virtual void function2()=0;
};

class Derived : public Base
{
    public:
       virtual void function2(){std::cout<<"2"<<std::endl;}
};

int main()
{
    Derived d;
    void ptr* = static_cast<void*>(&d);
    Base* baseptr=static_cast<Base*>(ptr);
    baseptr->function1();
    baseptr->function2(); 
}

这会编译并给出所需的结果(分别打印 12),但它可以保证工作吗? static_cast的描述我在这里找到:http://en.cppreference.com/w/cpp/language/static_cast 只提到转换为void* 并返回到指向 same 类的指针(第 10 点)。

【问题讨论】:

    标签: c++ static-cast


    【解决方案1】:

    在一般情况下,通过静态转换将基类转换为 void 到派生类(反之亦然)是不安全的。

    在某些情况下它几乎肯定会起作用:如果所涉及的一切都是 pod 或标准布局,并且只涉及单继承,那么事情应该没问题,至少在实践中:我没有章节和诗句从标准来看,但一般的想法是,在这种情况下,基数保证是派生的前缀,并且它们将共享地址。

    如果您想开始看到此失败,请混合使用virtual 继承、多重继承(virtual 和非)以及非平凡的多重实现继承。基本上当this 的不同类型视图的地址不同时,void 与不同类型之间的转换就注定了。我在实践中看到了这种失败,事实上它可能会失败(由于代码库中的更改远离转换点)这就是为什么你要小心 always 来回转换具有完全相同类型的 void 指针。

    【讨论】:

      【解决方案2】:

      一般来说,不,不安全。

      假设将Derived* 直接转换为Base* 会导致不同的地址(例如,如果涉及多重继承或虚拟继承)。

      现在,如果您在两者之间插入了对void* 的强制转换,编译器如何知道如何将该void* 转换为适当的Base* 地址?

      如果您需要将Derived* 转换为void*,则应首先将void* 显式转换回原始Derived* 类型。 (从那里开始,从Derived*Base* 的转换无论如何都是隐式的,所以你最终会得到相同数量的转换,因此实际上并没有那么方便。)

      【讨论】:

        【解决方案3】:

        来自您自己提供的链接

        9) 指向某个类 D 的成员的指针可以向上转型为指向其基类 B 的成员的指针。此 static_cast 不检查以确保该成员实际存在于所指向对象的运行时类型中。

        意思是只要你在做之前知道向上转换是安全的,它就可以保证工作。这就是为什么你应该使用dynamic_cast,如果不成功则返回nullptr

        如果有的话,可以这样想。

        Type * t1;
        

        static_cast 的 t1 到从它派生的类之一在编译时无法知道,除非对您的程序进行深入分析(显然它不是也不应该这样做),所以即使它最终是更正你没有办法检查。 dynamic_cast 在运行时做额外的工作来检查转换是否成功,因此前缀是动态的。

        【讨论】:

        • 但我正在向上转型(朝向基地)。我知道这总是安全的,但我担心在两者之间转换为void*
        • @Roberto 如果你知道这是一个有效的演员表,那么它是安全的,如果演员表有可能失败,那是不安全的
        • 我知道static_cast&lt;Base*&gt;(Derived*) 是安全的 - 你是说那static_cast&lt;Base*&gt;(static_cast&lt;void*&gt;(Derived*)) 也是安全的吗?
        • @Roberto 好吧,从某种意义上说,如果失败,它不会给出错误代码是不安全的
        • 对DV的任何评论
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-11
        • 2014-05-29
        • 1970-01-01
        • 2023-02-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多