0

是否有可能拥有std::list一个基类,将少数类型的子类放入其中,并访问子类成员迭代?

4

3 回答 3

3

如果您的元素类型是的,那么可以。

唯一的问题是您需要存储指向这些多态对象的指针,因为容器拥有它们的元素,如果您尝试将 a 添加Base到列表中,它将被复制和切片,失去其更多派生性质的所有上下文。如果它是一个抽象类(它应该是),那么代码甚至不会编译。

我建议不要使用原始指针,所以这就是我们得到的:

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

struct Base
{
   virtual ~Base() {}
   virtual void foo() = 0;
};

struct Derived1 : Base
{
   void foo() { std::cout << "Lol!\n"; }
};

struct Derived2 : Base
{
   void foo() { std::cout << "Haha!\n"; }
};

int main()
{
   typedef std::list<std::unique_ptr<Base>> list_type;

   list_type l;
   l.emplace_back(new Derived1());
   l.emplace_back(new Derived2());
   l.emplace_back(new Derived2());
   l.emplace_back(new Derived1());

   for (auto& x : l)
      x->foo();      // <-- this is a VIRTUAL function call!
}

输出

哈哈!
哈哈!
哈哈!
哈哈!

是的,它有点冗长,但你可以用包装函数和诸如此类的东西来整理它。

于 2013-08-15T14:25:37.850 回答
1

是的,这是可能的 - 但请确保存储指针而不是值以避免切片问题

#include <iostream>
#include <list>

struct Base {
  virtual ~Base() {}
  virtual void f() = 0;
};

struct DerivedA : Base {
  virtual void f() { std::cout << "DerivedA::f\n"; }
};

struct DerivedB : Base {
  virtual void f() { std::cout << "DerivedB::f\n"; }
};

int main()
{
  std::list<Base *> l;
  l.push_back( new DerivedA );
  l.push_back( new DerivedB );

  for ( std::list<Base *>::const_iterator it = l.begin(); it != l.end(); ++it ) {
    (*it)->f();
  }
}

这打印

DerivedA::f
DerivedB::f

与其存储原始指针,不如使用某种智能指针来处理delete适当的调用。C++11 具有各种智能指针,但请确保不要使用 std::auto_ptr

于 2013-08-15T14:28:52.570 回答
0

Derived由于切片,您不能放入std::list<Base>,但您可以使用指针(或更好的智能指针)来完成。

std::list<Base*> l;
l.push_back(new Derived); // don't forget to delete it!!

你可以打电话(*l.begin())->method_that_present_in_base()。如果此方法是虚拟的,则将调用派生的方法。

例子:

#include <iostream>
#include <list>

struct Animal {
    virtual void say() {
        std::cout <<"I'm generic animal\n";
    }

    virtual ~Animal(){}
};

struct Cat : public Animal {
    virtual void say() {
        std::cout << "Meow\n";
    }
    virtual ~Cat(){}
};

int main() {
    std::list<Animal*> l;
    l.push_back(new Animal);
    l.push_back(new Cat);
    for(Animal* ptr: l) {
        ptr->say();
    }
    for(Animal* ptr: l) {
        delete ptr; //not needed if you use smart pointers.
    }
}

输出

我是普通动物

于 2013-08-15T14:29:12.557 回答