是否可以拥有std::list
个基类,将几个类型的子类放入其中,并访问子类成员迭代?
答案 0 :(得分:3)
如果你的元素类型是多态,那么是。
唯一的问题是你需要存储指向那些多态对象的指针,因为容器拥有他们的元素,如果你试图在列表中添加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!
}
洛尔!
哈哈!
哈哈!
笑!
是的,它有点冗长,但你可以用包装函数和诸如此类的东西来整理它。
答案 1 :(得分:1)
是的,这是可能的 - 但请确保存储指针而不是值以避免slicing problem:
#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具有各种智能指针,但请确保not use std::auto_ptr!
答案 2 :(得分:0)
由于slicing,您无法将Derived
置于std::list<Base>
,但您可以使用指针(或更好smart pointers)来执行此操作。
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.
}
}
我是通用动物
喵