代码之家  ›  专栏  ›  技术社区  ›  Fred

C2440静态_cast无法从基类转换为派生类

  •  0
  • Fred  · 技术社区  · 8 年前

    我试图理解为什么使用指针从基类转换为派生类编译得很好,但使用非指针对象转换会产生错误C2440。

    下面我有一个基类 ThreadedMessage 这是由类继承的 GPSMessage .

    struct ThreadedMessage
    {
      ThreadedMessage()
        : m_Type(0), m_ID(0)
      { }
    
      ThreadedMessage(uint Type, uint ID = 0) :
        m_Type(Type), m_ID(ID)
      { }
    
      uint m_Type;
      uint m_ID;
    };    
    
    struct GPSMessage : public ThreadedMessage
    {
      GPSMessage()
        : ThreadedMessage()
      { }
    
      GPSMessage(double lat, double lon)
        : ThreadedMessage(1), m_lat(lat), m_lon(lon)
      { }
    
      double m_lat;
      double m_lon;
    };
    

    myFunction 我试图从基类强制转换到派生类。

    void myFunction(const ThreadedMessage& msg)
    {
      const GPSMessage* message = static_cast<const GPSMessage*>(&msg); // Compiles fine
      const GPSMessage message1 = static_cast<const GPSMessage>(msg);   // Error C2440
    }
    

    呼吁 myFunction() 看起来像这样:

    GPSMessage msg(21.123, 12.321);
    myFunction(msg);
    

    编译时,指针的强制转换可以正常编译,但非指针强制转换失败,出现以下错误:

    错误C2440:“static_cast”:无法从“const ThreadedMessage”转换为“const GPSMessage”。没有构造函数可以采用源类型,或者构造函数重载解析不明确

    为什么我不能用非指针变量从基类强制转换到派生类?

    是的,我看过其他类似的SO问题,但我读过的那些问题似乎没有回答我的问题。

    2 回复  |  直到 8 年前
        1
  •  4
  •   geza    8 年前

    这两种类型有不同的含义。

    第一组演员:

    const GPSMessage* message = static_cast<const GPSMessage*>(&msg); // Compiles fine
    

    这意味着 msg 实际上是一个 GPSMessage (或派生的)对象。你让编译器来威胁你 味精 作为一个 GPS消息 . 不会创建新对象, message 味精 . 如果 味精 GPS消息

    顺便说一句,以下铸件具有相同的含义(铸造为参考):

    const GPSMessage& message = static_cast<const GPSMessage&>(msg); // same meaning, which results in a reference instead of a pointer
    

    关于第二组演员:

    const GPSMessage message1 = static_cast<const GPSMessage>(msg);   // Error C2440
    

    新的 对象 message1 从…起 味精 . 您应该给出一种使这种转换成为可能的方法。例如,您应该为 GPS消息 哪个有一个 ThreadedMessage 参数:

    struct GPSMessage {
        GPSMessage(const ThreadedMessage &); // needed constructor
    };
    

    线程消息 GPS消息

    struct ThreadedMessage {
        operator GPSMessage(); // conversion operator
    };
    
        2
  •  2
  •   Some programmer dude    8 年前

    在函数中,编译器只知道 msg ThreadedMessage ,它不知道函数中真正作为参数传递的是什么。

    思考一下,如果您将引用传递给 实际的 对象或者从其他继承类引用另一个对象?

    投 反对 GPSMessage 对象,则需要进行转换,并且不可能进行这种转换( 线程消息 类没有转换运算符,并且 GPS消息 没有合适的构造函数)。

    唯一的解决方案是将指针或引用强制转换为另一个指针或引用。就像您在指针示例中所做的那样,或者通过执行例如。

    const GPSMessage& message1 = static_cast<const GPSMessage&>(msg);
    

    如果你真的想成为一名演员 GPS消息 对象 ,而不是引用或指针,那么最好的解决方案是使用转换构造函数:

    class GPSMessage : public ThreadedMessage
    {
    public:
        ...
        explicit GPSMessage(const ThreadedMessage& tm)
            : GPSMessage(static_cast<const GPSMessage&>(tm))  // Invoke copy-constructor
        {}
        ...
    };
    

    使用复制构造函数很好,但它要求 tm 争论真的吗 提及 GPS消息


    另一个解决方案是创建类 virtual )和使用 dynamic_cast 指向指针。如果结果是空指针,则 味精 那不是一个 GPS消息