有谁知道为什么 STL 容器没有虚拟析构函数?
据我所知,唯一的好处是:
- 它通过一个指针(指向虚拟方法表)减少实例的大小,并且
- 它使破坏和建造速度更快。
缺点是以通常的方式对容器进行子类化是不安全的。
编辑: 也许我的问题可以改写为“为什么不设计 STL 容器以允许继承?”
因为它们不支持继承,所以当一个人想要一个需要 STL 功能和少量附加功能的新容器(比如一个专门的构造函数或具有地图默认值的新访问器,管他呢):
- 组合和接口复制:创建一个新的模板或类,它拥有 STL 容器作为私有成员,并且每个 STL 方法都有一个直通内联方法。这与继承一样高效,避免了虚拟方法表的成本(在重要的情况下)。不幸的是,STL 容器具有相当广泛的接口,因此这需要很多行代码来完成看似容易做到的事情。
- 只需制作函数:使用裸(可能是模板化的)文件范围函数,而不是尝试添加成员函数。在某些方面,这可能是一个很好的方法,但封装的好处却丢失了。
- 具有公共 STL 访问权限的组合:让 STL 容器的所有者让用户访问 STL 容器本身(可能通过访问器进行保护)。这需要对库编写器进行最少的编码,但对用户来说不太方便。组合的一大卖点是减少了代码中的耦合,但此解决方案将 STL 容器与所有者容器完全耦合(因为所有者返回一个真正的 STL 容器)。
- 编译时多态性:编写起来可能有些棘手,需要一些代码练习,并且不适用于所有情况。
作为一个附带问题:是否有一种使用非虚拟析构函数进行子类化的标准安全方式(假设我不想覆盖任何方法,只是想添加新方法)?我的印象是,如果没有能力更改定义非虚拟类的代码,就没有通用且安全的方法来执行此操作。
编辑2:
正如@doc 指出的那样,C++ 11更高级的using
声明在一定程度上降低了组合成本。