将派生对象分配给函数内的基类指针

时间:2018-07-02 15:31:50

标签: c++ inheritance polymorphism object-slicing

我有一个基类,

  struct MsgFormat {
    MsgFormat();
    virtual ~MsgFormat();

    const std::string rootNode;
  };

和派生类

 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;
};

现在我有一个消息处理程序类,该类需要一个指向基类的指针,

  class MsgHandler
  {
  public:
    MsgHandler();
    virtual ~MsgHandler();

    virtual int parseIncoming(struct MsgFormat* pBaseMsg) = 0;
    virtual int formatOutgoing(const struct HermesMsgFormat* const pBaseMsg) = 0;
  };

};

现在,如果我在main()中这样做,

ServiceMsg* pSrvMsg = new ServiceMsg("foo", "bar");    
SpecificMsgHandler m_handle->formatOutgoing(pSrvMsg);

在重载的 formatOutgoing 方法中,我有类似的内容,

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;
}

其中 CustomMsgHandler 继承自 MsgHandler 类,一切都很好。我猜这就是多态的整个思想。您可以将派生类的对象传递到接受指向基类的指针的接口。


不起作用的是相反的情况。在 parseIncoming()执行以下操作的地方,

    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
    }

我在main()中执行以下操作。

MsgFormat* pBaseMsg = new pBaseMsg();
SpecificMsgHandler m_handle->parseIncoming(pBaseMsg);

但是,如果我尝试从main()中的pBaseMsg中读取,则从对 parseIncoming 消息的调用返回之后,我不会得到“ bla”和“ baa”。我得到了默认构造函数中设置的内容。

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;

我不明白为什么第二种情况不起作用。还是如何使其最佳运作?

1 个答案:

答案 0 :(得分:1)

您正在按值传递指针。该函数将复制您传入的指针,然后修改该副本。这就是为什么在函数调用后main中看不到更改的原因。

要解决此问题,您可以改为通过引用传递指针,方法是更改​​函数的签名。

virtual int CustomMsgHandler::parseIncoming(struct MsgFormat*& pBaseMsg) //added &, it's now a reference to a pointer.

还请注意,您首先要在main中进行动态分配。

MsgFormat* pBaseMsg = new pBaseMsg();

然后将这个指针传递给函数,然后再次进行动态分配。

pBaseMsg = new ServiceMsg("bla", "baa");

在这里您忘记了首先delete指针,所以您泄漏了内存。每次对new的调用都需要对delete进行调用以释放内存。 (除非将其传递给诸如智能指针的构造函数之类的东西,否则智能指针将为您进行delete处理。)

使用c ++ 11或Boost等效版本时
在现代C ++中,实际上不需要使用裸露的newdelete。您应该改用std::vectorstd::unique_ptrstd::shared_ptr之类的东西。