在C++中扩展容器(如std :: vector)的功能的正确方法,而不继承它?

Meh*_*dad 5 c++ inheritance stl

我一再读到,从STL容器继承是一件坏事.
(我知道这背后的原因是什么,这不是我的问题.)

牢记上述内容,扩展容器功能的正确方法是什么?

例如,如果我想要一个类似vector容器,当参数大于或等于容器的大小自动调整operator[]大小,我该怎么办?

对我来说,C++ 11中最明显的解决方案是:

template<class T, class A = std::allocator<T> >
class auto_vector : public std::vector<T, A>
{
    typedef std::vector<T, A> base_type;
public:
    using base_type::vector;
    typename base_type::reference operator[](typename base_type::size_type n)
    // I don't need const version, so I'll just ignore it here
    {
        if (n >= this->base_type::size())
        { this->base_type::resize(n + 1); }
        return this->base_type::operator[](n);
    }
};
Run Code Online (Sandbox Code Playgroud)

在C++ 03中,它将是:

template<class T, class A = std::allocator<T> >
class auto_vector : public std::vector<T, A>
{

    typedef std::vector<T, A> base_type;
public:
    explicit auto_vector(
        typename base_type::allocator_type const &alloc =
            typename base_type::allocator_type())
        : base_type(alloc) { }
    explicit auto_vector(
        typename base_type::size_type n,
        value_type const &val = value_type(),
        typename base_type::allocator_type const &alloc =
            typename base_type::allocator_type())
        : base_type(n, val, alloc) { }
    template<class InIt>
    auto_vector(InIt f, InIt l, typename base_type::allocator_type const &alloc =
                                typename base_type::allocator_type())
        : base_type(f, l, alloc) { }
    auto_vector(auto_vector const &v) : base_type(v) { }
    typename base_type::reference operator[](typename base_type::size_type n)
    // I don't need const version
    {
        if (n >= this->base_type::size())
        { this->base_type::resize(n + 1); }
        return this->base_type::operator[](n);
    }
};
Run Code Online (Sandbox Code Playgroud)

这两个都是不好的做法,因为他们继承了std::vector.

那么,实现这样的事情的"正确"方式是什么呢?

Che*_*Alf 4

首先,关于……

“我多次读到从 STL 容器继承是一件坏事。”

…参考文献提供了 STL 容器没有虚拟析构函数的原因。

对于新手来说,不要从没有虚拟析构函数的类中派生,这当然是个好建议。这使他们无法访问 中的受保护成员std::stack,使他们无法使用 Microsoft COM 技术等,但总而言之,对于新手来说,网络优势是巨大的。同样,我们建议新手不要使用原始数组和直接newand delete,遵循这对新手来说可能是一个巨大的净优势,但是,一些更有经验的人仍然必须这样做,必须实现新手的抽象(理想情况下) ) 限制使用,以免任何 C++ 程序中都没有动态分配。

因此,像这样的类std::stack清楚地表明关于此的绝对规则是无稽之谈,经验丰富的程序员必须权衡利弊,并且在决定继承时,必须在 和 继承之间public进行protected选择private

缺点公共继承:如果新手auto_vector动态分配 ,然后尝试通过使用delete指向 的指针来销毁它std::vector,那么设计就无法指导新手正确使用。所以如果是强烈引导新手正确使用的目标,那么要么不这样做,要么也添加让新手难以动态分配的功能。例如,添加一个operator new具有不可访问类型的附加参数,或者其本身不可访问。

对于当前的情况,其他多态访问 asstd::vector不是问题,因为索引 astd::vector超出其大小的代码已经具有未定义的行为。

对于其他情况,人们可以想象的情况,与OP的情况不同,必须考虑这些其他情况的细节:一般的绝对规则在编程中不起作用(好吧,至少在C++编程中不起作用)。

在这种情况下,支持公共继承:这是“我想要所有基类的功能”的最简单、最直接、最清晰的表达。