我反复阅读继承自STL容器is a Bad Thing (我知道这背后的原因是什么,这不是我的问题。)
牢记以上内容,扩展容器功能的正确方法是什么?
例如,如果我想要一个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);
}
};
在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);
}
};
这两种都是不好的做法,因为它们继承自std::vector
。
答案 0 :(得分:4)
首先,关于......
“我一再认为继承STL容器是一件坏事。”
...使用引用提供STL容器没有虚拟析构函数的原因。
对于新手而言,如果没有虚拟析构函数,那么这对于没有派生出来的课程肯定是个好建议。这使他们无法例如访问std::stack
中的受保护成员,它使他们无法使用Microsoft COM技术等,但总而言之,对于新手来说,净优势是巨大的。同样,我们建议初学者不要使用原始数组并指导new
和delete
,这对于初学者来说可能是一个巨大的净优势,但仍然,一些 - 更有经验 - 必须这样做,有实现新手(理想情况下)约束使用的抽象,以免在任何C ++程序中都没有动态分配。
因此,像std::stack
这样的类清楚地证明关于这一点的绝对规则是无意义的,有经验的程序员必须权衡利弊,在决定继承时,必须在public
之间进行选择,{ {1}}和protected
继承。
Con 公共继承:如果新手动态分配private
,然后尝试在指向auto_vector
的指针上使用delete
来销毁它,那么设计未能指导新手正确使用。因此,如果强烈指导新手纠正使用是一个目标,那么要么不这样做,要么添加使新手动态分配困难的功能。例如。添加std::vector
附加不可访问类型的参数,或者本身无法访问。
对于手头的情况,其他多态访问operator new
不是问题,因为将std::vector
索引超出其大小的代码已经具有未定义的行为。
对于其他情况,可以想象的情况,与OP的情况不同,必须考虑其他情况的细节:一般绝对规则不会在编程中削减它(好吧,至少在C ++编程中没有)。
在这种情况下,Pro 公共继承:它是“我想要所有基类”功能的最简单,最直接和最明确的表达方式。
答案 1 :(得分:1)
std::vector
中缺少虚拟析构函数是一个你不应该掉以轻心的标志。
组合几乎总是优于继承来扩展类型。在你的情况下你应该做的是撰写一个std::vector
,并且只重新实现你想要在其上使用的成员函数。最终不应该是一个大问题,因为对于给定的用例,很少使用std::vector
的整个公共接口的5-10以上。重新实现的功能只是将他们的调用转发给撰写的std::vector
,而您的新operator[]
会添加额外的调整大小逻辑。
通过这样做,我们无法像std::vector
那样意外地使用您的新类型。