C2440 static_cast无法从基类转换为派生类

时间:2018-11-14 06:56:25

标签: c++ casting polymorphism static-cast

我试图理解为什么使用指针从基类强制转换为派生类的编译效果很好,但是使用非指针对象进行强制转换会产生错误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”没有构造函数可以采用源类型,或者构造函数重载解析度不明确

为什么我不能使用非指针变量将基类转换为派生类?

编译器是MS VS 2008 C ++。

是的,我看过其他类似的SO问题,但是我看过的问题似乎并不能回答我的问题。

2 个答案:

答案 0 :(得分:3)

这两个演员具有不同的含义。

第一个演员

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

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

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

或为ThreadedMessageGPSMessage创建转换运算符:

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

答案 1 :(得分:2)

在函数中,编译器仅知道msg是对 ThreadedMessage 的引用,它不知道实际传递的是什么函数内部的参数。

考虑一下,如果传递对 actual ThreadedMessage对象的引用会发生什么情况?还是从其他继承的类中引用另一个对象?

要将对象从ThreadedMessage转换为GPSMessage对象,需要进行转换,并且这种转换是不可能的(ThreadedMessage类没有转换操作符,并且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对象的引用。否则无效。


另一种解决方案是使类成为 polymorphic (通过使析构函数virtual成为最简单的类),并使用dynamic_cast指向指针。如果结果为空指针,则msg并不是开头的GPSMessage