A Brief Look at C++中文版
Bjarne Stroustrup
AT&T Bell Laboratories
Murray Hill, New Jersey 07974
[原作者]:Bjarne Stroustrup (C++的设计者)
[翻译者]:Kingofark
[Kingofark的话]:这篇文章诚然已经不新了。但我想,尽可能多的读一读大师们的感思,总不至于是一件坏事情罢。因此还是费力翻译出来(Bjarne Stroustrup大师的英文文章可真是不太容易阅读!),试图截获一丝助人的快乐。
摘 要
本文有侧重点的回答了这样两个问题:C++是什么?C++在过去若干年中是如何演化发展的?有经验的C++用户应该把C++当作一个实用工具来看待。本文并无意把C++与其它语言作比较,然而我还是回答了一些特定的问题,这些问题经常被Lisp程序员问到。
1. 介绍
像所有现存的程序设计语言一样,C++在过去若干年中不断发展和变化着。对我而言,C++的发展速度是极为缓慢的;但发展不可避免,它体现着C++本身在内部机制方面自然的进化,也是对千千万万C++用户之使用心得的一种深思熟虑的回应。对于许多积极使用C++的人来说,这种发展慢得令人失望和丧气。对于一些不经常使用C++的人来说,这种发展好像一种不可预见的行为,晃晃悠悠滑入了未知。而对于其他人来说,C++只是一种虚无飘渺、对其知之甚少的东西,并且伴随着极其多的谣言围绕着它。
不管你如何看待C++,它与第一次出现的时候相比,已经有了相当可观的发展。举手例子来说明:一个简单的函数,其功能是对一个container排序,并计算排在Dahl和Nygaard之间的元素的个数:
template<class C> int cnt(C& v)
{
sort(c.begin(),v.end());
C::iterator d = find(v.begin(), v.end(), "Dahl");
return count(d, find(d, v.end(), "Nygaard"));
}
一个container可以看作是从begin()到end()的一系列元素之集合。在一个container中,用iterator来标识每一个元素。
只要container遵循C++标准库的一般原则,并且其元素可以与string literals作比较,那么这个template函数就可以如上所述正常运作。例如:
vector<char*> v; // C风格的字符串vector
list<string> lst; // C++中的string list
// ...
int i1 = cnt(v);
int i2 = cnt(lst);
其中,vector、list和string都是标准C++库的一部分。
很自然的是,我们不必在这样一个小小的函数里建立‘Dahl’和‘Nygaard’这样的string值。实际上,对于任意类型的container,我们都可以生成一个通用函数,使其能对任意类型的数值在某个范围内进行任意的操作。
显然,这里的编程风格与传统的C编程风格远不相同。然而,C++并没有因此而丧失掉C所具有的某些重要美德:可适应性和效率。例如,上面代码中使用的C++标准库中的算法sort()函数,在许多相对简单但有实际意义的例子中要比C标准库中的qsort()函数快上好几倍。
2. C++标准
C++是一种使用静态类型机制的(statically-typed)、通用目的(general-purpose)的语言,它通过类机制和虚拟函数机制来支持面向对象程序设计,通过模板机制来支持范型程序设计,并通过提供底层的语言设施来支持详细的系统程序设计。这个基本定义听起来还是相当不错的。尽管我并不认为定义中描述的那些方面可以在严格的意义上被证明,但是我已经看到了足够多的事实来使我对这个定义的合理性感到满意,这些事实包括足够多的优秀C++代码,以及使用C++进行的足够多的、成功的大规模工程。
到了1989年的时候,多种因素使得C++的标准化工作成为不可避免的一件事,被考虑到的因素包括C++用户的数量、独立的C++实现者以及C++工具的提供者的数目。而如果不做标准化工作,C++就会演变成一种“方言”。等到了1995年,ANSI和ISO C++标准委员会已经在对基本语言结构、标准库的特性和在描述上的精确性等级这三个方面的把握上达到了一定层级的稳定性,从而使C++标准的草案得以发布[Koenig,1995]。正式的标准将在1996年底或者1997年初发布。
在标准化工作的进程中,又有许多特性和库被增加到了C++中。总的来说,标准化工作确认并增强了C++最基本的特质,使其更为完整。关于C++中的一些新特性以及产生这些特性的原因,可以在[Stroustrup;1994]中找到相关叙述。对C++一些原始特性的讨论以及对一些还没被加入C++但正在考虑的特性之讨论,也可以在[Stroustrup;1994]中找到。
2.1 语言特性
标准C++基本上就是由《The C++ Programming Language (2nd Edition)》[Stroustrup,1991]中所描述的语言,再加上名字空间(namespace)、运行期类型(run-time type)信息以及另外几个次要的新特性组成的。在那些较小的改进当中,最明显的就是对模板机制的完善。
下面是一个用C++进行面向对象程序设计的经典例子:
class Shape {
virtual void draw() = 0:
virtual void rotate(int) = 0;
// ...
};
Shape是一个抽象类;这也就是说,Shape类型只是一个接口,而没有具体的实现。我们可以根据这个接口来定义出特定的类型。例如,下面的代码定义了Circle类型,它是Shape的一种:
class Circle : public Shape {
Point center;
int radius;
public:
Circle(Point, int); // 构造函数(constructor)
void draw();
void rotate(int) { }
// ...
};
这样我们就可以通过一个通用的接口来操作各种Shape型对象了。例如,下面的函数将任何Shape型向量旋转r个角度:
void rotate_all(vector<Shape*>& v, int r)
{
for (int i = 0; i<v.size(); i++) v[i]->rotate(r);
}
对于每一种特定的Shape型对象,其相应的rotate()函数被调用。比如,若被旋转的是Circle对象,那么Circle::rotate()会被调用。
考虑如下代码,它从流中读取Shapes:
void user(istream& ss)
{
io_obj* p = get_obj(ss); // 从流中读取对象
if (Shape* sp = dynamic_cast<Shape*>(p)) { // 是Shape型的吗?
sp->draw(); // 使用Shape型对象
// ...
}
else // 噢欧:不是shape型的
throw unexpected_shape();
}
在这里,dynamic_cast运算符用来检查对象是否确实是Shape型的。任何一种Shape——比如Circle——都是可以的。如果碰到对象不是一种Shape的情况,就抛出一个异常。
当然上面的例子没有什么实际意义。然而其中包含的技术和支持这些技术的语言特性曾被用在一些有史以来最大和最难的应用开发当中。
2.2 标准库
缺少一个完善的标准库一直都是C++最大的弱点之一。这个缺憾不但导致了各种不兼容“基础程序库(Foundation Libraries)”的迅猛出现,而且还使得刚入行的C++程序员不得不自行设计基本库设施,从而离完成任务的目标越来越远。后一种情况尤为恶劣,因为设计并实现一个优秀的基本库设施远要比使用一个困难得多。标准库的缺乏使得许多程序员在完全掌握基本的C++知识以前就被迫面对一些高级的C++特性。
标准库所提供的设施可以分为如下几类;
[1] 对基本的运行期语言支持(run-time language support)(比如内存分配、运行期类型识别等);
[2] 标准C库(为了使其与类型系统的冲突降到最低,进行了一些微小的修改);
[3] strings和输入输出流(用以支持国际性的字符集和本地化操作);
[4] 一个container的framework(比如vector,list和map等)以及使用这些container的算法(比如通用的遍历、排序和结合算法);
[5] 对数字计算的支持(复数以及向量的算术运算;类BLAS的、通用的slices;有利于优化处理的语意;等)。
将一个类包含在程序库里的主要原则有:这个类应该可能被几乎所有的C++程序员(不管是新手还是专家)使用;这个类应该以一种通用的形式被提供,但与实现相同功用的、更简单的形式相比,又不会带来明显的负荷;其基本用法很容易学会。总的来说,C++标准库提供了最常用的基本数据结构以及使用这些数据结构的基本算法。
对于程序库中的算法,任何container不需要经过类型等方面的转换操作就可以使用它。这个framework——通常被称作STL——具有可扩展性,使用户可以在标准库已提供的container和算法的基础上,方便的增加自己的container和算法,并使其可以直接与标准的container和算法共同使用。
3. 工具、环境和程序库
标准化工作完成之后所带来的各方面的稳定性,使得人们在编程环境、程序库和工具之生产方面的工作激增。在C++领域里,传统的工作目标一般是要创造这样一种C++语言,使得:即使在缺乏先进的工具和环境的情况下,人们也能在重大的工业项目中高效的使用C++。这并没有阻碍优秀C++工具和环境的出现,但语言本身的进化已经对语言的实现和工具集的制造产生了巨大的影响。
我期待着真正优秀的程序开发环境能在未来的几年里被全面应用。很多曾被人们认为不可能实现的针对C++的特性现在已经在某些商业产品中被实现了。比如Sun公司的C++实现允许你在一个
breakpoint处停止程序的执行,重写一个函数并以新函数重新执行。这种特性已经在具有动态类型(dynamically-typed)机制的解释型语言中存在数十年了。然而,这正是一种有趣且良好的发展,离我对程序开发环境所期望的目标又迈出了一步。在我的目标里,程序开发环境应该兼具基于静态类型的(statically-typed)语言之强大功能,和复杂的环境所带来的优势。而且这样一个复杂的环境,应该与基于动态类型的(dynamically-typed)语言之环境相类似。
庞大的C++用户群所带来的益处就是大量程序库的出现。现今已经出现了不计其数的C++程序库,但是各个编译器之间的差异以及标准的缺乏严重影响了程序库的发展。前一个问题引起了对程序库的不必要的分段(segmentation),并导致一些专门用于解决跨平台问题的程序库出现。后一个问题迫使开发者一遍又一遍的重复设计诸如string和list这样的基本设施。尽管仍需要多年的时间才能把这些问题完全从C++系统中解决掉,我们现在就已经有了替代方案,可以使我们把心思放到更重要也更有趣的方面上去。
垃圾自动收集机制(automatic garbage collection)也许对于C和Lisp这两种语言来说,都是格格不入的。Lisp语言坚持:内存管理太重要了,所以绝不能留给用户自己管理。而C语言则坚持:内存管理太重要了,所以绝不能让系统来管理。C++采取了一种折衷方案。C++允许使用垃圾自动收集机制,但又不强制使用它。从传统的观点来看,这即意味着C++不使用垃圾自动收集机制,但现在无论是商业的还是免费开放的垃圾收集器(garbage collector)之C++实现,都有其实际的用途。这些垃圾收集器的性能之良好是值得期待的,尤其比我数年来听到对其进行的悲观预言要好得多。甚至是在不使用垃圾收集器的时候,设计良好的C++程序因内存管理而遇到的麻烦也比传统的C程序少得多。在C++中,内存管理通常被封装在用户自定义的类型中,用户根本就不需要直接对内存进行分配和去配。特别是诸如string、vector和list这样的标准container,都有其自己的内存管理机制,并提供大小可变的数据结构。
4. 编程风格
C++是一种支持多种paradigm的语言。换句话说,C++语言被设计成能支持多种程序设计风格的形式。没有哪个语言能同时支持所有种类的程序设计风格。然而在一个语言的framework中却可以同时支持多种风格。这样做,我们就可以通过共享通用类型系统和通用工具集等设施的方法来得到颇为丰厚的收益。这些技术优势可以体现在一些重要的实际收效中,比如可以提供groups,以满足在共享一门语言时所提出的各种不尽相同的需要,这就比根据不同需要而特意实现几种特定的语言要划算得多。
对于C++新手,C++还支持传统的C程序设计风格。其它的程序设计风格则强调使用类、抽象类、类层次和模板等机制,以便直接的、清晰的、具象的体现各种概念以及各概念之间的关系。例如,本文第1节使用了范型程序设计技术,第2.1节又演示了抽象类和类层次的使用。
在C++程序设计风格(比如[Kornig,1995b]一书)和设计模式(比如[Gamma,1994]一书)方面所做的许多工作都着重于寻求一种方法,借以表达出来自各种语言和系统中的观点(idea),从而让那些编写大型系统的C++程序员能够高效率、高效益的运用这些观点。其关键就在于高效的运用C++中的这个具有可适应性和可扩展性的静态类型系统(static type system)。
5. 致谢
感谢Craig Knoblock邀请我撰写本文。
6. 参考
[Gamma,1994] Gamma, et.al.: Design Patterns. Addison Wesley. 1994. ISBN 0-201-63361-2.
[Koenig,1995] Andrew Koenig (editor): The Working Papers for the ANSI-X3J16 /ISO-SC22-WG21 C++ standards committee.
[Koenig,1995b] Andrew Koenig and Bjarne Stroustrup: Foundations for Native C++ Styles. Software– Practice & Experience. 1995.
[Stepanov,1994] Alexander Stepanov and Meng Lee: The Standard Template Library. ISO Programming language C++ project. Doc No: X3J16/94-0095, WG21/N0482.
[Stroustrup,1991] Bjarne Stroustrup: The C++ Programming Language (2nd Edition) Addison Wesley,ISBN 0-201-53992-6. June 1991.
[Stroustrup,1994] Bjarne Stroustrup: The Design and Evolution of C++ Addison Wesley, ISBN 0-201-54330-3. March 1994.