簡體   English   中英

g ++忽略覆蓋的虛函數

[英]g++ ignores overwritten virtual function

我有兩個這樣的類(簡化和重命名):

class Base
{
 public:
  virtual void operator()( ) { cout << "Base\n";}
};

class Derived : public Base
{
 public:
  void operator()( ) { cout << "Derived\n"; }
};

void doSomething( Base obj )
{
  obj( );
}

int main( )
{
  list<Base> bList;
  Derived d1, d2, d3;
  bList.push_back( d1 );
  bList.push_back( d2 );
  bList.push_back( d3 );

  for( list<Base>::iterator it = bList.begin(); it != bList.end(); it++ )
    {
      doSomething( *it );
    }
  return 0;
}

運行此命令時,我得到:

Base
Base
Base

即調用Base :: operator()。 顯然,這不是我想要的。 我嘗試將doSomething更改為

void doSomething( Base& obj )

但這僅適用於直接用“派生”對象而不是列表中的一個調用的情況。 並且引用不能存儲在列表中。
有什么方法可以使doSomething“看到”它必須調用派生類的函數(而不必求助於指針)?

編輯:指出了問題,對於其他可能會遇到此問題的人,這里是一個鏈接: 什么是對象切片?

下列:

list<Base> bList;
Derived d1, d2, d3;
bList.push_back( d1 );
bList.push_back( d2 );
bList.push_back( d3 );

切片您的對象。 它們不再是Derived類型,而是Base類型。 您需要在容器中使用指針或智能指針以實現預期的行為。

閱讀對象切片。

問題不在於編譯器沒有“看到”它需要在派生類中調用函數,而是在於您僅將基類存儲在容器list<Base> 這導致通常稱為對象切片的結果。 當編譯器將您的Derived對象復制到只能容納Base對象的容器中時,它只能復制該對象的基礎部分,並從使其成為Derived對象的部分上“切片”。

為了對遵循值語義的容器使用多態性(即,假設您將實際對象存儲在其中,而不是對對象的引用形式),需要存儲指向所述對象的指針。 我建議不要將原始指針存儲在標准庫容器中,因為它會引入其他生命周期管理問題-您必須從容器外部控制指向對象的生存期,這通常是一個非常糟糕的主意,通常導致內存泄漏或指針懸空(如果不能同時發生)。

我的建議是,如果可以使用boost,請使用為此目的明確設計的ptr_container模板類之一。 如果不能,並且您使用的是足夠現代的編譯器,則可以使用std::list<std::shared_ptr<Base> > >並依靠shared_ptr來管理對象的生命周期。

上面的答案使我找到了最終的解決方案。 簡短的答案是:“否。您必須使用指針列表。” 這是我想出的...

#include <iostream>
#include <memory>
#include <list>

class Base
{
    public:
        virtual void foo()
        {
            std::cout << "Base::foo" << std::endl;
        }
};

class Derived : public Base
{
    public:
        void foo()
        {
            std::cout << "Derived::foo" << std::endl;
            Base::foo();
        }
};

int main()
{
    std::list<std::shared_ptr<Base>> bases;
    auto p = std::make_shared<Derived>();
    bases.push_back(p);

    for (std::list<std::shared_ptr<Base>>::iterator i = bases.begin(); i != bases.end(); i++)
    {
        (*i)->foo();
    }

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM