views:

114

answers:

3

Environment: Linux C++ / Qt 4x

I do not understand why the following downcast returns NULL? I pasted base and derived class below.

Thanks in advance for any tips or suggestions.

-Ed

void MainWindow::onRtledaEventHandler(fes::EventArgs eventArgs)
{
   // This cast returns a NULL ?
   fes::AtsCommandEventArgs* atsCommandEventArgs = dynamic_cast<fes::AtsCommandEventArgs*>(&eventArgs);
}


/// The base class for containing event arguments sent to clients using boost::signals2
class EventArgs
{
public:

   EventArgs() {}
   EventArgs(RtledaEventType eventType) :
         m_eventType(eventType) {}
   EventArgs(const EventArgs& eventArgs) :
         m_eventType(eventArgs.m_eventType) {}
   virtual ~EventArgs() {}

   /// The type of event this is
   RtledaEventType eventType() const { return m_eventType; }

protected:
   RtledaEventType m_eventType;
};

// Derived class I am trying to upcast to
class AtsCommandEventArgs : public EventArgs
{
public:
   /// \param [in] lraddsPacketError LRADDS oacket error structure
   /// \sa fes::StructPacketStats_t packetStats
   AtsCommandEventArgs(fes::AtsCommand atsCommand, std::string messageBuffer, std::string details) :
         EventArgs(RtledaEventTypeAtsCommand),
         m_atsCommand(atsCommand),
         m_messageBuffer(messageBuffer),
         m_details(details) {}

   AtsCommandEventArgs(const AtsCommandEventArgs& AtsCommandEventArgs) :
         EventArgs(AtsCommandEventArgs),
         m_atsCommand(AtsCommandEventArgs.m_atsCommand),
         m_messageBuffer(AtsCommandEventArgs.m_messageBuffer),
         m_details(AtsCommandEventArgs.m_details) {}

   AtsCommandEventArgs() {}
   ~AtsCommandEventArgs() {}

   fes::AtsCommand atsCommand() const { return m_atsCommand; }
   std::string messageBuffer() const { return m_messageBuffer; }
   std::string details() const { return m_details; }

private:
   fes::AtsCommand m_atsCommand;
   std::string m_messageBuffer;
   std::string m_details;
};

Thanks in advance for any tips or suggestions,

-Ed

A: 

dynamic_cast<> returns NULL if the types between you are wanting to cast are unrelated, or if you have provided it a NULL pointer to cast. The checking is performed on hte type info in thanx to the RTTI, and you can trust it.

So there's these two possibilities only.

Either eventArgs is not a AtsCommandEventArgs or eventArgs references a NULL object (horror!)

Like others have noticed, you pass the eventArgs by value, so the AtsCommandEventArgs part of the object is not copied to. As they have told you, pass the AtsCommandEventArgs by pointer or by references.

Stephane Rolland
I did not provide it a NULL pointer to cast. Therefore my derived class must not be a derived properly somehow. Thanks for your help.
Ed
A: 

The only way for an upcast to return null-pointer is when you pass a null-pointer as an argument for the cast.

The second possibility is this case is that your are thinking that you are performing an upcast, while in reality it is not an upcast. You haven't shown any code that calls the function with the cast, so there's no way to say what is happening there.

Looking at your code: there's no upcast in your code. What you are trying to do is a downcast. And the argument you passed to the function is passed by value, which means that it got sliced in the process. No wonder the downcast fails. It should fail. You have to pass either by pointer or by reference to use dynamic_cast.

P.S. Don't use HTML tags to format code on SO. Use the "Code" button.

AndreyT
@Stephane Rolland: Incorrect. It is not possible to "upcast a wrong type". Upcast is an upcast. If it is really an *upcast*, it always succeeds. There's no RTTI involved in upcasts. For upcasts, `dynamic_cast` is exactly equivalent to `static_cast`.
AndreyT
@Stephane Rolland: Great. But, once gain, my statement above clearly stays: "The only way for an *upcast* to return null-pointer is when you pass a null-pointer as an argument for the cast". Do you have any problems with this specific statement? If not, then what other statement are you addressing by your first comment?
AndreyT
@Stephane Rolland: Your first comment begins with "no, ...", meaning that it is intended to be an objection to one of my previous statements. Which of my statements are you objecting to?
AndreyT
@Stephane Rolland: And, of course, one should note that if the types are totally unrelated, the `dynamic_cast` will simply not compile. `dynamic_cast` returns null-pointer (or throws in case of references) when the types are *related*, but the dynamic type is wrong and the run-time cast fails.
AndreyT
@Audrey, i remove my comments away since you think they are not acurate.
Stephane Rolland
+9  A: 

You are passing a fes::EventArgs object by-value, which means it is a fes::EventArgs object. If you want to preserve the original type of polymorphic objects, pass a pointer or (better) a reference to them:

void MainWindow::onRtledaEventHandler(fes::EventArgs& eventArgs) {
   fes::AtsCommandEventArgs& atsCommandEventArgs = dynamic_cast< fes::AtsCommandEventArgs&>(eventArgs);
}

Note that dynamic_cast throws std::bad_cast in case of failure if applied to references.

Alexander Gessler
Perfect! Thank you very much for all your advice and pointing out my error.I will change it to a reference.Thanks again,
Ed
If your question has been answered, consider accepting the answer that has helped you most.
Alexander Gessler
... and, of course, consider noting that it is a *downcast*, not an *upcast* :)
AndreyT
Thanks. I finally figured out how to accept an answer. I suppose it should have been obvious but it was not ( click on the check mark outline ). :-)Right, I was actually trying to downcast and not upcast. Down as in down from the base class to a derived class as opposed to upcasting or up the inheritance tree.
Ed