std容器中的抽象类

Her*_*ert 13 c++ virtual-functions c++11

通常,当我编程时,我使用多态,因为它自然地模拟我需要的对象.另一方面,我经常使用标准容器来存储这些对象,我倾向于避免使用指针,因为这要求我释放对象而不是将它们从堆栈中弹出或要求我确定对象将保持不变我使用指针时的堆栈.当然有各种各样的指针容器对象可以为你完成这项任务,但根据我的经验,它们也不理想甚至烦人.那是; 如果存在这样一个简单的解决方案,它本来就是用c ++语言,对吧?;)

所以让我们有一个经典的例子:

#include <iostream>
#include <vector>

struct foo {};
struct goo : public foo {};
struct moo : public foo {};

int main() {
    std::vector<foo> foos;
    foos.push_back(moo());
    foos.push_back(goo());
    foos.push_back(goo());
    foos.push_back(moo());

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

请参阅:http://ideone.com/aEVoSi.这工作正常,如果对象具有不同的sizeof,编译器可能会应用切片.但是,由于c ++不知道像Java这样的实例,并且据我所知,没有足够的替代存在,在从向量中获取它们作为foo之后,无法访问继承类的属性.

因此,人们将使用虚函数,但是这不允许一个人分配foo,因此不允许在向量中使用它们.请参阅为什么我们不能声明std :: vector <AbstractClass>?.

例如,我可能希望能够打印两个子类,简单的功能,对吗?

#include <iostream>
#include <vector>

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

struct goo : public foo {
    int a;
    void print() { std::cout << "goo"; }
};

struct moo : public foo {
    int a,b;
    void print() { std::cout << "moo"; }
};

int main() {
    std::vector<foo> foos;
    foos.push_back(moo());
    foos.push_back(goo());
    foos.push_back(goo());
    foos.push_back(moo());

    for(foo& f : foos) {
        f.print();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

资料来源:http://ideone.com/I4rYn9

这是一个简单的补充,作为一个设计师我永远不会想到在远见中想要这种行为.由于c ++能够切割我的对象并因此在一个向量中存储不同大小的对象,我已经非常激动了.不幸的是,当基类是抽象的时,它不能再这样做了,如下所述:为什么我们不能声明一个std :: vector <AbstractClass>?

一般的好解决方案似乎是使用指针.但是这(1)迫使我做内存管理和(2)我需要改变接口并重新编写很多东西.例如,考虑到我首先有一些类接口返回一个std :: vector <foo>,现在它返回一个std :: vector <foo*>,所以我需要检查并更改foo的所有调用; 如果我正在写一个图书馆,这很烦人,甚至不可能.

所以基本上,imho,这是一个小功能添加大代码后果.

我的问题是编码标准.我怎样才能防止这些烦恼发生?我应该总是使用指针,并进行所有内存管理吗?我是否应该总是认为课程可能会变得抽象?

编辑,答案:基于40的两个答案,我制作了这个片段:

#include <iostream>
#include <vector>
#include <memory>

struct foo {
    virtual void print() =0;
};

struct goo : public foo {
    int a;
    void print() { std::cout << "goo"; }
};

struct moo : public foo {
    int a,b;
    void print() { std::cout << "moo"; }
};
typedef std::unique_ptr<foo> foo_ptr;
int main() {
    std::vector<std::unique_ptr<foo> > foos;
    foos.push_back(foo_ptr(new moo));
    foos.push_back(foo_ptr(new goo));
    foos.push_back(foo_ptr(new goo));
    foos.push_back(foo_ptr(new moo));

    for(auto it = foos.begin(); it!=foos.end(); ++it) {
        it->get()->print();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

资料来源:http://ideone.com/ym4SY2

101*_*010 11

如果编译器支持C++ 11功能,一种解决方案是使用std::vector<std::shared_ptr<foo>>std::vector<std::unique_ptr<foo>>代替原始指针,如下例所示:

#include <iostream>
#include <memory>
#include <vector>

struct foo {
    virtual void print() = 0;
};

struct goo : public foo {
    int a;
    void print() { std::cout << "goo"; }
};

struct moo : public foo {
    int a,b;
    void print() { std::cout << "moo"; }
};

auto main() -> int {
    std::vector<std::shared_ptr<foo>> v{std::make_shared<goo>(), std::make_shared<moo>()};
    for(auto i : v) { 
        i->print();
        std::cout << std::endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

或者std::vector<std::unique_ptr<foo>>:

auto main() -> int {
    std::vector<std::unique_ptr<foo>> v;
    v.push_back(std::move(std::unique_ptr<goo>(new goo)));
    v.push_back(std::move(std::unique_ptr<moo>(new moo)));
    for(auto it(v.begin()), ite(v.end()); it != ite; ++it) { 
        (*it)->print();
        std::cout << std::endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

因此,您不必担心内存释放.

  • 首选`std :: unique_ptr`到`std :: shared_ptr`. (2认同)

4pi*_*ie0 5

您可以使用原始指针并正确处理内存

std::vector< AbstractBase*>
Run Code Online (Sandbox Code Playgroud)

或者您可以使用智能指针,即std::shared_ptr(通过指针保留对象的共享所有权的std::unique_ptr智能指针)或(通过指针保留对象的唯一所有权并unique_ptr在超出范围时销毁该对象的智能指针),然后该库为您执行内存管理。所以你最终会遇到类似

std::vector< std::shared_ptr<AbstractBase>>
Run Code Online (Sandbox Code Playgroud)

要么

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

http://en.cppreference.com/w/cpp/memory/shared_ptr http://en.cppreference.com/w/cpp/memory/unique_ptr

  • 将`std :: unique_ptr`优先于`std :: shared_ptr`。 (2认同)
  • 我什至会说“更喜欢[value_ptr](https://bitbucket.org/martinhofernandes/wheels/src/a3365a24524e4e7c05754689bf44fae160e5ed83/include/wheels/smart_ptr/value_ptr.h%2B%2B?at=default)尽管这是C ++社区中的争论点,但在“ unique_ptr”和“ shared_ptr”两者上都是如此。 (2认同)