我试图理解为什么从基类转换到使用指针的派生类编译罚款,但使用非指针对象产生错误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问题,但似乎我已经阅读了那些不回答我的问题。
这两种类型转换有不同的含义。
第一投:
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
};
或创建一个转换操作符ThreadedMessage
到GPSMessage
:
struct ThreadedMessage {
operator GPSMessage(); // conversion operator
};
在编译器只知道功能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
开始。