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
};
我试图理解为什么使用指针从基础 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
};