拥有多态对象集合的首选C++习惯用法是什么?

Ant*_*ois 17 c++ polymorphism c++11

考虑以下类

class Base {
public:
    virtual void do_stuff() = 0;
};

class Derived : public Base {
public
    virtual void do_stuff() { std::cout << "I'm useful"; };
};
Run Code Online (Sandbox Code Playgroud)

现在让我们说我想让另一个类负责拥有Base派生类型的对象,并通过它们调用它们的do_stuff()方法进行迭代.它看起来像这样,但我不知道T应该声明什么

class Owner {
public:
    void do_all_stuff() {
        //iterate through all items and call do_stuff() on them
    }

    void add_item(T item) {
        items.push_back(item);
    }

    vector<T> items;
}
Run Code Online (Sandbox Code Playgroud)

我看到了一些可能性:

T不可能Base,因为我只能添加具体类型的对象Base,所以这是不可能的.

T可以是Base*Base&,但现在我需要信任调用者add_item()传递一个指针或对一个对象的引用,当我从中检索它时它仍然存在items.我不能解析析构函数中delete的元素Owner,因为我不知道它们是动态分配的.但是,他们应该是delete'如果他们是,这让我拥有模糊的所有权.

T可以Base*或者Base&我添加一个Base* create_item<DerivedT>() { return new DerivedT; }方法Owner.这样,我知道指针将保持有效并且我拥有它,但是我无法调用非默认构造函数DerivedT.此外,还Owner负责实例化对象.我还必须删除Owner析构函数中的每个项目,尽管这不是问题.

基本上,我希望能够做类似的事情:

Owner owner;

void add_one() {
    Derived d;

    owner.add_item(d);
}

void ready() {
    owner.do_all_stuff();
}

void main() {
    for(int i = 0; i < 10; ++i) {
        add_one();
    }
    ready();
}
Run Code Online (Sandbox Code Playgroud)

我确信在那里有一些与移动语义相关的东西(我可以移动传递给add_items()它们的对象)但是我仍然无法弄清楚我的集合是如何被声明的.

这种多态所有权的C++习语是什么(特别是对于STL容器)?

bam*_*s53 19

多态对象必须由指针或引用处理.由于它们的生命周期可能不受特定范围的约束,因此它们也可能具有动态存储持续时间,这意味着您应该使用智能指针.

智能指针如std::shared_ptrstd::unique_ptr工作只是在标准集合类型的罚款.

std::vector<std::unique_ptr<Base>>
Run Code Online (Sandbox Code Playgroud)

使用它Owner看起来像:

class Owner {
public:
    void do_all_stuff() {
        //iterate through all items and call do_stuff() on them
    }

    void add_item(std::unique_ptr<Base> item) {
        items.push_back(std::move(item));
    }

    vector<std::unique_ptr<Base>> items;
}
Run Code Online (Sandbox Code Playgroud)

参数类型用于add_item标识添加项目所需的所有权策略,并要求用户尽力将其搞砸.例如,它们不会意外地使用一些隐含的,不兼容的所有权语义传递原始指针,因为unique_ptr它具有显式构造函数.

unique_ptr还将负责删除所拥有的对象Owner.虽然您确实需要确保Base具有虚拟析构函数.根据您当前的定义,您将获得未定义的行为.多态对象应该总是有一个虚拟析构函数.