Why is the C++ STL is so heavily based on templates? (and not on *interfaces*)(为什么 C++ STL 如此大量地基于模板?(而不是在*接口*上))
问题描述
我的意思是,除了它的强制性名称(标准模板库)...
I mean, aside from its obligating name (the Standard Template Library)...
C++ 最初打算将 OOP 概念呈现到 C 中.也就是说:您可以根据其类和类层次结构来判断特定实体可以做什么和不能做什么(无论它如何做).由于多重继承的问题,以及 C++ 以一种有点笨拙的方式支持接口概念的事实(与 java 等相比),一些能力的组合更难以用这种方式描述,但它就在那里(并且可能是改进).
C++ initially intended to present OOP concepts into C. That is: you could tell what a specific entity could and couldn't do (regardless of how it does it) based on its class and class hierarchy. Some compositions of abilities are more difficult to describe in this manner due to the problematics of multiple inheritance, and the fact that C++ supports the concept of interfaces in a somewhat clumsy way (compared to java, etc), but it's there (and could be improved).
然后模板和 STL 一起发挥了作用.STL 似乎采用了经典的 OOP 概念,并使用模板来代替它们.
And then templates came into play, along with the STL. The STL seemed to take the classical OOP concepts and flush them down the drain, using templates instead.
当模板用于泛化类型的情况之间应该有区别,其中类型本身与模板的操作(例如容器)无关.拥有一个 vector
非常有意义.
There should be a distinction between cases when templates are used to generalize types where the types themeselves are irrelevant for the operation of the template (containers, for examples). Having a vector<int>
makes perfect sense.
然而,在许多其他情况下(迭代器和算法),模板类型应该遵循一个概念"(输入迭代器、前向迭代器等...),其中概念的实际细节完全由实现定义模板函数/类,而不是模板使用的类型的类,这在某种程度上是 OOP 的反用法.
However, in many other cases (iterators and algorithms), templated types are supposed to follow a "concept" (Input Iterator, Forward Iterator, etc...) where the actual details of the concept are defined entirely by the implementation of the template function/class, and not by the class of the type used with the template, which is a somewhat anti-usage of OOP.
比如你可以告诉函数:
void MyFunc(ForwardIterator<...> *I);
更新: 由于在原始问题中不清楚,ForwardIterator 可以被模板化以允许任何 ForwardIterator 类型.相反,将 ForwardIterator 作为一个概念.
Update: As it was unclear in the original question, ForwardIterator is ok to be templated itself to allow any ForwardIterator type. The contrary is having ForwardIterator as a concept.
仅通过查看其定义来期望前向迭代器,您需要查看其实现或文档:
expects a Forward Iterator only by looking at its definition, where you'd need either to look at the implementation or the documentation for:
template <typename Type> void MyFunc(Type *I);
我可以提出两个支持使用模板的声明:通过为每个使用的类型定制编译模板,而不是使用 vtables,可以使编译后的代码更高效.以及模板可以与本机类型一起使用的事实.
Two claims I can make in favor of using templates: compiled code can be made more efficient, by tailor-compiling the template for each used type, instead of using vtables. And the fact that templates can be used with native types.
然而,我正在寻找一个更深刻的原因,为什么放弃经典的 OOP 而支持 STL 的模板?(假设你读了那么远:P)
However, I am looking for a more profound reason why abandoning classical OOP in favor of templating for the STL? (Assuming you read that far :P)
推荐答案
简短的回答是因为 C++ 已经向前发展了".是的,早在 70 年代后期,Stroustrup 就打算创建具有 OOP 功能的升级版 C,但那是很久以前的事了.到 1998 年该语言标准化时,它已不再是 OOP 语言.它是一种多范式语言.它当然支持 OOP 代码,但它也覆盖了图灵完备的模板语言,允许编译时元编程,人们发现了泛型编程.突然之间,OOP 似乎不再那么重要了.当我们可以使用模板和泛型编程中可用的技术编写更简单、更简洁和更高效的代码时,情况并非如此.
The short answer is "because C++ has moved on". Yes, back in the late 70's, Stroustrup intended to create an upgraded C with OOP capabilities, but that is a long time ago. By the time the language was standardized in 1998, it was no longer an OOP language. It was a multi-paradigm language. It certainly had some support for OOP code, but it also had a turing-complete template language overlaid, it allowed compile-time metaprogramming, and people had discovered generic programming. Suddenly, OOP just didn't seem all that important. Not when we can write simpler, more concise and more efficient code by using techniques available through templates and generic programming.
OOP 不是圣杯.这是一个可爱的想法,而且它比 70 年代发明时的过程语言有了很大的改进.但老实说,这并不是它被破解的全部.在许多情况下,它既笨拙又冗长,并没有真正促进可重用代码或模块化.
OOP is not the holy grail. It's a cute idea, and it was quite an improvement over procedural languages back in the 70's when it was invented. But it's honestly not all it's cracked up to be. In many cases it is clumsy and verbose and it doesn't really promote reusable code or modularity.
这就是今天 C++ 社区对泛型编程更感兴趣的原因,也是为什么每个人终于开始意识到函数式编程也非常聪明的原因.OOP 本身并不好看.
That is why the C++ community is today far more interested in generic programming, and why everyone are finally starting to realize that functional programming is quite clever as well. OOP on its own just isn't a pretty sight.
尝试绘制一个假设的OOP 化"STL 的依赖图.有多少班级必须相互了解?将会有很多的依赖项.您是否能够只包含 vector
标头,而不会同时引入 iterator
甚至 iostream
?STL 使这变得容易.向量知道它定义的迭代器类型,仅此而已.STL 算法一无所知.它们甚至不需要包含迭代器头,即使它们都接受迭代器作为参数.哪个更模块化?
Try drawing a dependency graph of a hypothetical "OOP-ified" STL. How many classes would have to know about each others? There would be a lot of dependencies. Would you be able to include just the vector
header, without also getting iterator
or even iostream
pulled in? The STL makes this easy. A vector knows about the iterator type it defines, and that's all. The STL algorithms know nothing. They don't even need to include an iterator header, even though they all accept iterators as parameters. Which is more modular then?
STL 可能不遵循 Java 定义的 OOP 规则,但它是否实现了 OOP 的目标?不是实现了复用性、低耦合性、模块化和封装性吗?
The STL may not follow the rules of OOP as Java defines it, but doesn't it achieve the goals of OOP? Doesn't it achieve reusability, low coupling, modularity and encapsulation?
它是否比 OOP 化版本更好实现了这些目标?
And doesn't it achieve these goals better than an OOP-ified version would?
至于为什么在语言中采用 STL,有几件事导致了 STL.
As for why the STL was adopted into the language, several things happened that led to the STL.
首先,模板被添加到 C++ 中.添加它们的原因与将泛型添加到 .NET 的原因大致相同.能够在不丢弃类型安全的情况下编写诸如类型 T 的容器"之类的东西似乎是一个好主意.当然,他们确定的实现要复杂得多,而且功能强大得多.
First, templates were added to C++. They were added for much the same reason that generics were added to .NET. It seemed a good idea to be able to write stuff like "containers of a type T" without throwing away type safety. Of course, the implementation they settled on was quite a lot more complex and powerful.
然后人们发现他们添加的模板机制比预期的更强大.有人开始尝试使用模板来编写更通用的库.一种受函数式编程启发,另一种使用了 C++ 的所有新功能.
Then people discovered that the template mechanism they had added was even more powerful than expected. And someone started experimenting with using templates to write a more generic library. One inspired by functional programming, and one which used all the new capabilities of C++.
他将它提交给了 C++ 语言委员会,后者花了很长时间才习惯了它,因为它看起来如此奇怪和不同,但最终意识到它比他们必须使用的传统 OOP 等价物更有效包括其他.所以他们对其进行了一些调整,并将其纳入标准库.
He presented it to the C++ language committee, who took quite a while to grow used to it because it looked so strange and different, but ultimately realized that it worked better than the traditional OOP equivalents they'd have to include otherwise. So they made a few adjustments to it, and adopted it into the standard library.
这不是意识形态的选择,也不是我们是否要成为 OOP"的政治选择,而是一个非常务实的选择.他们评估了这个库,发现它运行良好.
It wasn't an ideological choice, it wasn't a political choice of "do we want to be OOP or not", but a very pragmatic one. They evaluated the library, and saw that it worked very well.
无论如何,您提到的支持 STL 的两个原因都是绝对必要的.
In any case, both of the reasons you mention for favoring the STL are absolutely essential.
C++ 标准库必须高效.如果它比等效的手动 C 代码效率低,那么人们就不会使用它.这会降低生产力,增加出现错误的可能性,而且总体来说是个坏主意.
The C++ standard library has to be efficient. If it is less efficient than, say, the equivalent hand-rolled C code, then people would not use it. That would lower productivity, increase the likelihood of bugs, and overall just be a bad idea.
并且 STL 必须使用原始类型,因为原始类型是 C 中的全部,并且它们是两种语言的主要部分.如果 STL 不适用于本机数组,它将无用.
And the STL has to work with primitive types, because primitive types are all you have in C, and they're a major part of both languages. If the STL did not work with native arrays, it would be useless.
您的问题有一个强有力的假设,即 OOP 是最好的".我很好奇为什么.你问他们为什么放弃经典的 OOP".我想知道他们为什么要坚持下去.它有哪些优势?
Your question has a strong assumption that OOP is "best". I'm curious to hear why. You ask why they "abandoned classical OOP". I'm wondering why they should have stuck with it. Which advantages would it have had?
这篇关于为什么 C++ STL 如此大量地基于模板?(而不是在*接口*上)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么 C++ STL 如此大量地基于模板?(而不是在*接
基础教程推荐
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 从 std::cin 读取密码 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01