2016-05-16 64 views
0

我有两个类型类Ll2TxPacketBds和Ll2TxLbPacketBds后一类从定义为现有类继承的如下:C++多态性/虚拟功能这里不工作

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

,你可以看到子类reimplemets虚拟BD方法。 有随后定义为父亲指针类型的出队:

deque<Ll2TxPacketBds*> m_txPacketList; 

使用推动元件为双端队列的两种不同的方式如下:

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正确调用构造函数...

如果弹出的元素用方法#1中创建多态性会不会发生,Ll2TxPacketBds实施bd(..)将始终被调用,而方法#2如同多态一样按预期工作。

+0

此代码似乎被混淆了。 – perencia

+4

您正在将临时对象的地址推送到队列中。当你退出完成推送的块时,你会有悬挂指针和UB。 –

+0

它不是正在切片,因为它重新定义了一个虚拟方法,但不添加新的成员或方法 – Hillel

回答

5

你不能把一个堆栈分配对象的基指针,因为它被破坏,你只剩下指针到不再存在的对象的基础部分。所以它实际上是未定义的行为,因为该对象不再存在,它只是运气(有时),这正是UB通常如何显示的。

的解决办法是更换:

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

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

然后取消分配您在容器中保存的东西。为此你需要使析构函数变得虚拟!

你可以将它变成智能指针,它可以为你节省解除分配,但你仍然需要虚拟析构函数(即使在基类中是空的)。

+0

即使push和pop都发生在同一个函数中? – Hillel

+1

@Hillel在你的代码中,它不会发生在同一个块中,这是一个问题。如果它在同一个模块中,它应该按预期工作,虽然这是非常奇怪的设计。块(非功能)结束时,对象被销毁。 – Resurrection