没有人知道为什么STL容器没有虚拟析构?

尽我所知,唯一的好处是:

  • 它减小的一个实例,通过一个指示器(以虚拟方法表)和
  • 这使得破坏和建造一个微小的位速度更快。

缺点是,它是不安全的子类容器可在通常的方式。

编辑: 也许是我的问题可以重新措辞,"为什么不STL容器的设计允许用于继承权?"

因为他们不支持继承,一是坚持以下选择当一个人想要有一个新的容器,需要补功能以及少量的其他功能(说一个专门的构造或新的访问,与默认值的地图,或无论):

  • 组成和接口的复制:做一个新的模板或类拥有STL容器作为一个私人部件和具有一个通过内联的方法为每个STL方法。这只是作为高性能作为继承,避免了成本的虚拟方法表(在的情况下,事项)下。不幸的是,STL容器必须相当广泛的接口,因此这需要许多行代码的东西,似乎应该是很容易做到。
  • 只是做功能:使用裸(可能的模板)的文件范围的职能,而不是试图添加功能的构件。在某些方面,这可以是一个很好的做法,但利益的封装。
  • 组成公共STL访问:有的拥有者STL容器允许用户访问了STL容器本身(或许是守卫通过访问).这就要求至少编码的图书馆的作家,但它更便于用户使用。其中一个大卖点组成是减少联接在你的代码,但这种解决方案全面情侣STL容器的所有者的容器(因为所有者返回一个真正的STL容器)。
  • 编制时的多:可能有点棘手写的,需要一些代码体操,不是适用于所有情况。

作为一个方面的问题:是否有一个标准的安全方式的继承与非虚拟析构(让我们假设,我不希望复盖任何方法,只是我想添加新的)?我的印象是,没有通用和安全的方式这样做,如果一个没有改变的力量的代码定义的非虚拟课。

编辑2:

作为 @doc指出, C++11的票友 using 声明,以降低成本的组成。

有帮助吗?

解决方案

我想这下的C++的理念不支付特点,你不用。根据平台、指针为虚拟表可能是一个沉重的代价,如果你不关心有一个虚拟析构函数。

其他提示

一个虚拟析构是只适用于继承的情况。STL容器的设计并不是继承的(它也不是一个支持的设想)。因此他们没有虚拟析构函数。

我认为Stroustrup回答这个问题,间接地在他的梦幻般的文件: 为什么C++是不是只是一个面向对象编程语言:

7闭幕发言
是的各个 设施的提出上 面向对象或是不?哪些?使用什么定义 面向对象?在大多数情况下,我 认为这些都是错误的问题。重要的是什么想法你可以 表达清楚,如何容易地可以 结合起来的软件,从不同的 来源,以及如何有效率和 维护所得到的节目 是。换句话说,怎么你的支持 好的编程技术和良好 设计技术事项的多 标签和嗡嗡声的话。根本 想法是根本改进和设计 编程的通过抽象概念。你的 想要隐藏的细节,你想 利用任何共同性的系统, 和你想使这个负担得起的。我谨鼓励你在不来 让一个面向对象没有意义 术语。这一概念的"面向对象" 太经常贬值

–通过 把它具有良好的,

–通过把 它有一个单一的语言,或

–通过 接受一切 面向对象.

我们认为, 没–必须的–有用的 技术,超越了面向对象 编程和设计。然而,到 避免被完全误会了,我 想要强调的是我 不尝试一个严重的项目 使用一种编程语言, 没有至少支持经典 这一概念的面向对象编程。此外,设施,支持 面向对象编程,我想– 和C++提供的功能去 除了这些在他们的支持 直接表达的概念和 的关系。

STL建有三个概念性的工具中心主。 通用程序+功能的风格数据的抽象==STL风格.这是不奇怪的是,面向对象是没有的 最好的 的方式来表示一个数据结构和算法的图书馆。虽然面向对象是使用在其他地区的标准库,设计者为STL看到的,混合的三提到的技术是更好的比面向对象 单独.在短期,图书馆不是设计用面向对象的中心,并在C++如果你不用它,它没有得到附带的代码。你不付出什么,你不用。这类标准::矢量、性传染疾病::列表...都 面向对象的概念在Java/C#意义。他们只是 抽象的数据类型 在最好的解释。

为什么不STL容器的设计允许用于继承?

在我看来他们。如果他们不会,他们已经做了 最终.当我看到 stl_vector.h 源码我可以看到,我STL实现使用 受保护的 继承的 _Vector_base<_Tp, _Alloc> 授予访问权限于源类别:

 template<typename _Tp, typename _Alloc = allocator<_Tp> >
 class vector : protected _Vector_base<_Tp, _Alloc>

它不会使用 继承权,如果子类是不欢迎?


是否有一个标准的安全方式的继承与非虚拟析构(让我们假设,我不希望复盖任何方法,只是我想添加新的)?

为什么不用 protectedprivate 继承权和获得所需的部件的接口 using 关键字?

class MyVector : private std::vector<int>
{
     typedef std::vector<int> Parent;

     public:
        using Parent::size;
        using Parent::push_back;
        using Parent::clear;
        //and so on + of course required ctors, dtors and operators.
};

这种方法确保类的用户不会垂头丧气的实例 std::vector<int> 他是安全的,因为唯一的问题是与非虚拟析构,它不会叫源之一,当一个物体被删除,为一个实例父类。

...我也有松散的想法,你甚至可以继承公开如果你的班级没有一个析构函数。异教?

正如已经指出的那样,STL容器的设计并不是可继承的。没有虚拟方法,所有数据成员都是私有的,没有受到保护干将/者/助手..并且你已经发现,没有虚拟析构..

我建议你真的应该是使用集装箱通过组成,而不是执行继承中,在"有一个"的方式,而不是一个"是"之一。

你不应该盲目增加一个虚拟析构到每一类。如果是这种情况下,语言也不允许您的任何其他选择。当你加入一个虚拟的方法一类,没有任何其他虚拟方法,你只增加的大小类实例中通过大小的指针,通常为4个字节。这是昂贵的,这取决于你在做什么。大增加是因为v表是为了保持清单的虚拟方法,以及每个实例,需要指回v表。它通常位于第一单元的实例。

另一个解决方案能够子类从STL容器是一个由Bo谦使用智能指针。

先进C++:虚拟析构和智能析构

class Dog {
public:
   ~Dog() {cout << "Dog is destroyed"; }
};

class Yellowdog : public Dog {
public:
   ~Yellowdog() {cout << "Yellow dog destroyed." << endl; }
};


class DogFactory {
public:
   static shared_ptr<Dog> createYellowDog() { 
      return shared_ptr<Yellowdog>(new Yellowdog()); 
   }    
};

int main() {
    shared_ptr<Dog> pd = DogFactory::createYellowDog();

    return 0;
}

这样可以避免的dillema与虚拟析构。

如果你真的需要虚拟析构,可以添加这类中衍生的矢量<>,然后使用这类作为一个基类无处不在,你要虚拟的接口。通过这样做compilator会叫虚拟析构从基类,这反过来将电话非虚拟析构从矢量级。

例如:

#include <vector>
#include <iostream>

using namespace std;

class Test
{
    int val;
public:
    Test(int val) : val(val)
    {
        cout << "Creating Test " << val << endl;
    }
    Test(const Test& other) : val(other.val)
    {
        cout << "Creating copy of Test " << val << endl;
    }
    ~Test()
    {
        cout << "Destructing Test " << val << endl;
    }
};

class BaseVector : public vector<Test>
{
public:
    BaseVector()
    {
        cout << "Creating BaseVector" << endl;
    }
    virtual ~BaseVector()
    {
        cout << "Destructing BaseVector" << endl;
    }
};

class FooVector : public BaseVector
{
public:
    FooVector()
    {
        cout << "Creating FooVector" << endl;
    }
    virtual ~FooVector()
    {
        cout << "Destructing FooVector" << endl;
    }
};

int main()
{
    BaseVector* ptr = new FooVector();
    ptr->push_back(Test(1));
    delete ptr;

    return 0;
}

这个代码提供以下产出:

Creating BaseVector
Creating FooVector
Creating Test 1
Creating copy of Test 1
Destructing Test 1
Destructing FooVector
Destructing BaseVector
Destructing Test 1

没有虚拟析构防止类子类的正确。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top