问题
I am attempting to understand why casting from a base class to an derived class using pointers compiles fine, but casting using non-pointer object produces the error C2440.
Below I have a base class ThreadedMessage
that is inherited by 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;
};
In myFunction
I am attempting to cast from the base class to the derived 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
}
The call to myFunction()
looks like this:
GPSMessage msg(21.123, 12.321);
myFunction(msg);
When I compile, the casting of a pointer compiles fine, but the non-pointer casting fails with the following error:
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
Why am I unable to cast from the base class to the derived class with non-pointer variables?
Compiler is MS VS 2008 C++.
Yes, I have looked at other similar SO questions, but the ones I have read don't seem to answer my question.
回答1:
These two casts have differing meaning.
The first cast:
const GPSMessage* message = static_cast<const GPSMessage*>(&msg); // Compiles fine
This means that msg
is actually a GPSMessage
(or a derived) object. You ask the compiler to threat msg
as a GPSMessage
. No new object will be created, message
will point to msg
. If msg
is not actually a GPSMessage
(or derived), then this cast has Undefined Behavior.
Btw, the following cast have the same meaning (casting to a reference):
const GPSMessage& message = static_cast<const GPSMessage&>(msg); // same meaning, which results in a reference instead of a pointer
About the second cast:
const GPSMessage message1 = static_cast<const GPSMessage>(msg); // Error C2440
This means, that you create a new object, message1
from msg
. You should give a way to make this conversion possible. For example, you should create a constructor for GPSMessage
which has a ThreadedMessage
parameter:
struct GPSMessage {
GPSMessage(const ThreadedMessage &); // needed constructor
};
Or create a conversion operator for ThreadedMessage
to GPSMessage
:
struct ThreadedMessage {
operator GPSMessage(); // conversion operator
};
回答2:
In the function the compiler only knows that msg
is a reference to a ThreadedMessage
, it doesn't know what's really passed as an argument inside the function.
Think about what happened if you passed a reference to an actual ThreadedMessage
object? Or a reference to another object from some other inherited class?
To cast from an ThreadedMessage
object to a GPSMessage
object, a conversion is needed, and there's no such conversion possible (the ThreadedMessage
class doesn't have a conversion operator, and GPSMessage
doesn't have a suitable constructor).
The only solution is to cast pointers or references to another pointer or reference. Like you do in the pointer example, or by doing e.g.
const GPSMessage& message1 = static_cast<const GPSMessage&>(msg);
If you really want to cast to a GPSMessage
object, not reference or pointer, then the best solution is to use a conversion constructor:
class GPSMessage : public ThreadedMessage
{
public:
...
explicit GPSMessage(const ThreadedMessage& tm)
: GPSMessage(static_cast<const GPSMessage&>(tm)) // Invoke copy-constructor
{}
...
};
Using the copy-constructor is nice, but it requires that the tm
argument really is a reference to a GPSMessage
object. Otherwise it's invalid.
Another solution is to make the classes polymorphic (simplest by making the destructors virtual
) and use dynamic_cast
to a pointer. If the result is a null pointer then msg
wasn't a GPSMessage
to begin with.
来源:https://stackoverflow.com/questions/53294643/c2440-static-cast-cannot-convert-from-base-class-to-derived-class