I have a base class,
struct MsgFormat {
MsgFormat();
virtual ~MsgFormat();
const std::string rootNode;
};
and a derived class,
class ServiceMsg : public MsgFormat {
public:
explicit ServiceMsg(std::string A, std::string B);
ServiceMsg();
ServiceMsg(const ServiceMsg& srvMsg);
class ServiceMsg& operator=(const ServiceMsg& srvMsg);
~ServiceMsg();
std::string A() const;
std::string B() const;
private:
std::string m_A;
std::string m_B;
};
Now I have a message handler class, that takes a pointer to the base class, like this,
class MsgHandler
{
public:
MsgHandler();
virtual ~MsgHandler();
virtual int parseIncoming(struct MsgFormat* pBaseMsg) = 0;
virtual int formatOutgoing(const struct HermesMsgFormat* const pBaseMsg) = 0;
};
};
Now, if I do something like this in the main(),
ServiceMsg* pSrvMsg = new ServiceMsg("foo", "bar");
SpecificMsgHandler m_handle->formatOutgoing(pSrvMsg);
and inside the overloaded formatOutgoing method, I have something like this,
virtual int CustomMsgHandler::formatOutgoing(const struct MsgFormat* const pBaseMsg)
{
const ServiceMsg* const pServiceMsg = dynamic_cast<const ServiceMsg* const>(pBaseMsg);
std::cout << pServiceMsg->A() << std::endl;
std::cout << pServiceMsg->B() << std::endl;
}
where CustomMsgHandler was inherited from the MsgHandler class, all is fine and good. And that is I guess the whole idea of polymorphism. You can pass objects of a derived class to an interface that accepts a pointer to the base-class.
What does not work is, the opposite. Where parseIncoming() does the following,
virtual int CustomMsgHandler::parseIncoming(struct MsgFormat* pBaseMsg)
{
pBaseMsg = new ServiceMsg("bla", "baa");
#ifdef NDEBUG
ServiceMsg* pServiceMsg = dynamic_cast<ServiceMsg*>(pBaseMsg);
std::cout << pServiceMsg->A() << std::endl;
std::cout << pServiceMsg->B() << std::endl;
std::cout << "all good here" << std::endl;
#endif
}
I do the following in the main().
MsgFormat* pBaseMsg = new pBaseMsg();
SpecificMsgHandler m_handle->parseIncoming(pBaseMsg);
But if I try to read from pBaseMsg in the main(), after returning from the call to parseIncoming message, I don't get the "bla" and "baa". I get what was set in the default constructor.
ServiceMsg* pServiceMsg = dynamic_cast<ServiceMsg*>(pBaseMsg);
std::cout << pServiceMsg->A() << std::endl;
std::cout << pServiceMsg->B() << std::endl;
std::cout << "all good here" << std::endl;
I don't understand why this 2nd case does not work. Or how best to make it work?
You are passing the pointer by value. The function will make a copy of the pointer you pass in, you then modify the copy. That's why the changes are not visible in main
after the function call.
To fix this you can pass the pointer by reference instead, by changing the signature of the function.
virtual int CustomMsgHandler::parseIncoming(struct MsgFormat*& pBaseMsg) //added &, it's now a reference to a pointer.
Also note that you are first doing a dynamic allocation in main
.
MsgFormat* pBaseMsg = new pBaseMsg();
Then you pass this pointer to the function and again do a dynamic allocation.
pBaseMsg = new ServiceMsg("bla", "baa");
Here you forgot to delete
the pointer first, so you leaked memory. Every call to new
needs to have a call to delete
to free the memory. (Unless it's passed to something like the constructor of a smart-pointer, then the smart-pointer will take care of delete
ing for you.)
When using c++11 or the boost equivalents
There is really no need to use bare new
and delete
in modern C++. You should instead use things like std::vector
, std::unique_ptr
and std::shared_ptr
.