doc*_*7b5 17 c++ inheritance vector libstdc++
所以我一直在使用从std :: vector派生的容器.也许这是一个糟糕的设计决定,原因有几个,而且你是否应该做这样的事情的问题在这里有广泛的讨论:
我确信我已经错过了一些讨论......但是在链接中找到了两个观点的合理论据.据我所知,"因为~vector()是非虚拟的"是你不应该从stl容器继承的"规则"的基础.但是,如果我在g ++ 4.9.2中查看std :: vector的实现,我发现std :: vector继承自_Vector_base,而_Vector_base是非虚拟析构函数.
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
{
...
~vector() _GLIBCXX_NOEXCEPT
{ std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
_M_get_Tp_allocator()); }
...
}
Run Code Online (Sandbox Code Playgroud)
哪里:
template<typename _Tp, typename _Alloc>
struct _Vector_base
{
...
~_Vector_base() _GLIBCXX_NOEXCEPT
{ _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage
- this->_M_impl._M_start); }
...
}
Run Code Online (Sandbox Code Playgroud)
所以std :: vector的gcc 4.9.2实现继承自带有非虚析构函数的基类.这让我相信这是一种可接受的做法.为什么这样好?这种做法没有危险的具体条件是什么?
Cor*_*lks 15
std::vector不继承自_Vector_base或者更确切地说,不是在我的标准库实现中.libc ++实现了这样的向量:
namespace std
{
template <class T, class Allocator = allocator<T> >
class vector
{
...
Run Code Online (Sandbox Code Playgroud)
当然,您的实现可能继承自基类,但我的实现没有.这导致您对"规则"的解释出现第一个错误:
C++标准库可以通过多种方式实现,我们实际上无法从一个实现中对标准库(由其定义的标准库)做出广泛,全面的假设或陈述ISO/IEC 14882:2014.
所以,在我们进一步讨论之前,让我们记住:在这个答案中我们不会专注于单个实现.我们将考虑所有实现(通过关注C++标准中的定义;而不是硬盘驱动器上特定头文件的定义).
std::vector继承自己_Vector_base但在我们继续之前,让我们承认你的实现可能会继承_Vector_base,而且没关系.那么为什么std::vector允许从基类继承,但是你不允许继承std::vector?
std::vector,如果你想(只是要小心)std::vector可以继承_Vector_base你可以继承的相同原因std::vector:库实现者非常小心(你应该也是).
std::vector不是delete多态的_Vector_base指针.所以我们不必担心~vector()不虚拟.如果你没有delete带有多态std::vector指针的继承类,那么~vector()非虚拟就不是问题.没关系.别担心.我们不要大惊小怪.没有多态性delete意味着我们不必担心析构函数是否是虚拟的.
但除此之外,库实现者保证std::vector永远不会切片使用一个_Vector_base参考.对你来说也是一样的:如果你能确保你的自定义矢量类永远不会切片(有人使用std::vector它的参考),那么你也可以.没有切片意味着我们不必担心制作不良副本.
std::vector在其他问题中已经回答了很多问题,但我会在这里再说一遍(并且整个_Vector_base继承问题的重点):你(可能)不应该继承std::vector.
问题是,如果你这样做,使用你的自定义矢量类的人可能会多态地删除它(他们可能有一个std::vector指向它的指针,delete如果他们这样做,那就是一个坏事).或者他们可能会std::vector引用您的自定义对象并尝试复制它(这将切割对象,这也可能是一件坏事)(我一直假设需要std::vector引用自定义对象来导致对象切片复印时,因为我一直假设你足够细心从不小心切片的对象与粗心转让或函数调用,你绝不会这么不小心,我敢肯定,但别人有std::vector参考可能(是的,我在这里有点滑稽)).
您可以控制对代码执行的操作.如果你能够(小心地)控制它(确保)没有多态delete或对象切片,你就没事了.
但有时你无法真正控制别人对你的代码做什么.如果你在一个团队工作,如果一个团队成员无意中做了其中一件事,这可能会有问题.这就是我继续提出"小心"的原因.
更糟糕的是,如果您的代码被客户使用,您实际上无法控制他们所做的事情,如果他们做了其中一件坏事,那么您可能会受到指责并负责修复它(有兴趣重构过去依赖于继承的自定义类的所有代码std::vector)(或者只是告诉客户端他们不能这样做,但你可能会有一个脾气暴躁的客户浪费时间调试他们没有的奇怪问题期待碰上).
但是,您的C++标准库实现者可以放弃这种继承,因为它们可以很好地控制事物:不允许任何人使用_Vector_base.你可以用std::vector.只有std::vector.由于您不允许(永远)使用_Vector_base,标准库实现者不必担心对象切片或多态delete.而且由于他们在受控环境中的实施非常谨慎,所以事情就好了.
但更好的是,通过不对如何std::vector实现进行假设,而是将其视为(有用的)黑盒子,我们可以确保我们如何使用std::vector它可移植到其他标准库实现.如果您假设std::vector从某个基类继承,那么您将限制代码的可移植性.
| 归档时间: |
|
| 查看次数: |
1039 次 |
| 最近记录: |