C2440的static_cast不能从基类转换为派生类(C2440 static_cast can

2019-09-30 01:38发布

我试图理解为什么从基类转换到使用指针的派生类编译罚款,但使用非指针对象产生错误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:不能从“常量ThreadedMessage”到“常量GPSMessage”没有构造函数转换可采取源类型,或构造函数重载决议是暧昧

为什么我无法从基类转换为与非指针变量的派生类?

编译器是MS VS 2008 C ++。

是的,我已经看过其他类似的SO问题,但似乎我已经阅读了那些不回答我的问题。

Answer 1:

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

第一投:

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来自msg 。 你应该给一个办法,使这个转换成为可能。 例如,您应该创建一个构造GPSMessage具有ThreadedMessage参数:

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

或创建一个转换操作符ThreadedMessageGPSMessage

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


Answer 2:

在编译器只知道功能msg是一个参考ThreadedMessage ,不知道发生了什么作为函数内的参数是否真的过去了。

想想,如果你传递给实际的参考发生了什么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对象。 否则,它是无效的。


另一种解决方案是(通过使析构最简单,使类多晶型 virtual ),并使用dynamic_cast一个指针。 如果结果是一个空指针然后msg不是GPSMessage开始。



文章来源: C2440 static_cast cannot convert from base class to derived class