C ++多态性/虚函数在这里不起作用

时间:2016-05-16 09:09:44

标签: c++ inheritance polymorphism

我有两种类型的Ll2TxPacketBds和Ll2TxLbPacketBds,后一类继承自前面定义的类,如下所示:

class Ll2TxPacketBds
{
public:
    Ll2TxPacketBds(MainCorePfDrv *pCorePfDrv, const MainEthTxPacketDesc &pktDesc, uint32 pktProd);
    Ll2TxPacketBds(Ll2TxPacketBds&& moveFrom);  //Move Constructor
    ~Ll2TxPacketBds();

    virtual core_tx_bd_union bd(uint8 nSge, uint32 pktProd);
    uint8 sglSize() const;

protected:
    MainEthTxPacketDesc m_pktDesc;
    vector<shared_ptr<DrvBuf>> m_vectDrvBuf;
    uint8 m_txDst; // diffrent bd for loop back packet
};

class Ll2TxLbPacketBds : public Ll2TxPacketBds
{
public:
    Ll2TxLbPacketBds(MainCorePfDrv *pCorePfDrv, const MainEthTxPacketDesc &pktDesc, uint32 pktProd) : Ll2TxPacketBds(pCorePfDrv, pktDesc, pktProd) {};
    Ll2TxLbPacketBds(Ll2TxLbPacketBds&& moveFrom) : Ll2TxPacketBds((Ll2TxPacketBds&&)moveFrom) {};
    ~Ll2TxLbPacketBds() { Ll2TxPacketBds::~Ll2TxPacketBds(); };

    core_tx_bd_union bd(uint8 nSge, uint32 pktProd);
};

你可以看到son类重新实现了虚拟bd方法。 有一个父指针类型的队列定义如下:

deque<Ll2TxPacketBds*> m_txPacketList;

使用两种不同的方法将元素推入deque中,如下所示:

1

Ll2TxPacketBds* bd = (m_txDest != CORE_TX_DEST_LB) ? &Ll2TxPacketBds(m_pCorePfDrv, *pPktDesc, m_pktProd) : &Ll2TxLbPacketBds(m_pCorePfDrv, *pPktDesc, m_pktProd);
    m_txPacketList.push_back(bd); // Polymorphism/virtual function not working here

2

 if (m_txDest != CORE_TX_DEST_LB)
    {
        Ll2TxPacketBds* bd = &Ll2TxPacketBds(m_pCorePfDrv, *pPktDesc, m_pktProd);
        m_txPacketList.push_back(bd);

    }
    else
    {
        Ll2TxLbPacketBds* bdLb = &Ll2TxLbPacketBds(m_pCorePfDrv, *pPktDesc, m_pktProd);
        m_txPacketList.push_back(bdLb); //Works here
    }

弹出元素后,调用bd()如下:

m_pBdRing->peekProd() = m_txPacketList.back()->bd(nBd, m_pktProd); 

使用调试器我确实在#1和#2中看到正确的构造函数被调用...

如果popped元素是由方法#1创建的,那么多态性将不会发生,并且Ll2TxPacketBds实现bd(..)将始终被调用,而方法#2按预期工作,就多态性而言。

1 个答案:

答案 0 :(得分:6)

您不能获取堆栈分配对象的基指针,因为它会被销毁,而您只剩下指向不再存在的对象基础部分的指针。所以它实际上是未定义的行为,因为该对象不再存在,它只是运气(有时),这正是UB通常表现出来的。

解决方案是替换:

Ll2TxPacketBds* bd = &Ll2TxPacketBds(m_pCorePfDrv, *pPktDesc, m_pktProd);

Ll2TxPacketBds* bd = new Ll2TxPacketBds(m_pCorePfDrv, *pPktDesc, m_pktProd);

然后释放您保存在容器中的内容。为此,您还需要将析构函数设置为虚拟化!

您可以将其设置为智能指针,这将节省您的释放,但您仍然需要虚拟析构函数(即使在基类中为空)。