C2440 static_cast 无法从基础 class 转换为派生 class

C2440 static_cast cannot convert from base class to derived class

我试图理解为什么使用指针从基础 class 转换为派生 class 可以正常编译,但使用非指针对象进行转换会产生错误 C2440。

下面我有一个基础 class ThreadedMessage 被 class 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 中,我试图从基础 class 转换为派生的 class。

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

当我编译时,指针转换编译正常,但非指针转换失败并出现以下错误:

error C2440: 'static_cast' : cannot convert from 'const ThreadedMessage' to 'const GPSMessage' No constructor could take the source type, or constructor overload resolution was ambiguous

为什么我无法使用非指针变量从基 class 转换为派生 class?

编译器是 MS VS 2008 C++。

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

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

想一想如果传递对 actual ThreadedMessage 对象的引用会发生什么?或者从其他一些继承的对象中引用另一个对象 class?

要从 ThreadedMessage 对象转换为 GPSMessage 对象,需要进行转换,但不可能进行这种转换(ThreadedMessage class有转换运算符,GPSMessage 没有合适的构造函数)。

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

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

如果你真的想转换为GPSMessage对象,而不是引用或指针,那么最好的解决方案是使用转换构造函数:

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

使用复制构造函数很好,但它要求 tm 参数确实 GPSMessage 对象的引用。否则无效。


另一个解决方案是使classes 多态(最简单的方法是使析构函数virtual)并使用dynamic_cast指向指针.如果结果是空指针,则 msg 不是 GPSMessage 开头。

这两个转换具有不同的含义。

第一位演员:

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

这意味着msg实际上是一个GPSMessage(或派生的)对象。您要求编译器将 msg 威胁为 GPSMessage。不会创建新对象,message 将指向 msg。如果 msg 实际上不是 GPSMessage(或派生的),则此转换具有未定义的行为。

顺便说一句,以下转换具有相同的含义(转换为引用):

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

这意味着,您从 msg 创建了一个 new 对象,message1。您应该提供一种使这种转换成为可能的方法。例如,您应该为 GPSMessage 创建一个具有 ThreadedMessage 参数的构造函数:

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

或者为ThreadedMessage创建一个转换运算符到GPSMessage:

struct ThreadedMessage {
    operator GPSMessage(); // conversion operator
};