第一篇 C++C++C++C++基础
如果说有一种语言定义了当今编程的实质,那么它就是 C++。它是高性能软件开发的杰
出语言。它的语法已经成为专业编程语言的标准,并且它的设计思想在计算界引起深刻的反
响。
Java 和 C#语言都是从 C++继承而来的。简而言之,要成为专业的编程人员就意味着要
深刻理解 C++。它是现代编程的基础。
本篇旨在介绍 C++,包括它的历史,它的设计思想,以及几个最重要的特性。学习一门编
程语言最困难的事情就是所有的元素都不是单独孤立存在的。相反,构成语言的各个部分是
相互协作,一起工作的。这种相关性使得我们很难讨论 C++的一个方面而不去考虑其它方
面。为了克服这个困难,本篇对几个 C++特性进行了简单的介绍,包括 C++程序的通用形
式,一些基本的控制语句,以及运算符。本篇不会涉及过多的细节,更注重 C++程序中通
用的概念。
必备技能 1.11.11.11.1 C++C++C++C++历史简介
C++是从 C 语言发展而来的。这一点不难理解,因为 C++是构筑的 C 语言的基础之上
的。然而,C++是 C 语言的超集。C++扩展并增强了 C 语言,支持面向对象的编程(这点
在本篇的后面会进行描述)。C++同时对 C 语言做了改进,包括扩展了例行程序库集。然
而大部分的 C++特性是直接从 C 继承而来的。因此,为了充分理解和欣赏 C++,我们必须
深入了解 C 语言是如何运作的。
C:C:C:C: 现代编程时代的开始
C 语言的发明定义了现代编程时代的开始。它的影响不应该被低估,因为它从根本上改
变了人们考虑和实现程序的方法。它的设计思想和语法已经影响到了每一个主流的编程语
言。C 语言是计算发展的主要的,革命性的推动力之一。
C 语言由 Dennis Ritchie 在 DEC PDP-11 电脑上,在 UNIX 操作系统下发明并实现的。C
语言是从一种古老的叫做 BCPL 的语言发展而来。BCPL 是由 Martin Richards 开发的。
BCPL 语言对由 Ken Thompson 发明的 B 语言产生着深刻的影响,而 B 语言最终在 20 世
纪 70 年代发展成 C 语言。
在 C 语言发明之前,计算机语言被设计出来或者是为了进行学术计算,或者是为官方的
委员们所使用。而 C 却不同。它是一群真实的程序员设计、实现并开发出来的。它反映了
这些人完成编程工作的方法。它的特性是这群实际使用这个语言的人们反复推敲,打磨,测
试的结果。因此,C 语言吸引了众多的拥护者,并迅速成为全世界编程人员的选择。
C 语言的发展经历了 20 世纪 60 年代的结构化编程的革命。在此之前,大型程序是难以
书写的,因为程序的逻辑趋向于退化成“意大利面条式的代码”,充斥着难以理解的,混乱的
转跳,函数调用和返回。结构化编程通过增加很好的控制语句,带有局部变量的子程序段和
其它的一些改进解决了这个问题。结构化编程使得编写巨大的程序成为了可能。尽管还有别
的结构化的编程语言,例如 Pascal,C 却是第一个功能强大,富于表达,能书写出优美代
码的结构化语言。它语法简单易用,并且它的设计思想是程序员掌控一切,而不是语言本身
掌控一切,这就使得 C 语言很快拥有了众多的拥护者。我们现在来看这点可能有点难以理
解,但是 C 当时确实为编程者带来了他们渴望已久的新鲜空气。因此,C 语言很快就在 20
世纪 80 年代变成了使用最广泛的结构化编程语言。
我们需要 C++C++C++C++
经过前文的描述,你可能会问,那为什么还要发明 C++呢?既然 C 是很优秀的编程语言,
我们为什么还需要别的编程语言呢?这个问题的答案非常复杂。纵观编程技术的发展历史,
程序复杂度的增加驱使我们需要更好的方式来管理我们的程序。C++就应运而生了。为了更
好地理解增长的程序复杂度与计算机编程语言发展之间的关系,我们需要简单回顾一下计算
机编程技术发展的历史。当计算机刚被发明出来的时候,人们使用计算机前面的面板,通过
拨动开关来发送二进制的机器指令。这种方式在计算机程序只有几百行的时候还可以工作。
随着计算机程序的增大,人们发明了汇编语言,通过使用符号代替机器指令,以便程序员可
以处理更大的,更复杂的程序。第一个被广泛使用的计算机语言是 FORTRAN。FORTRAN
语言在起初给人的印象是非常深刻的,当时几乎没有语言能实现编写整洁,易于理解的程序。
20 世纪 60 年代,结构化编程诞生了,这正是诸如 C 语言一样的语言所鼓励的编程方法。
通过结构化的编程方法,很轻松的编写大型程序第一次成为了可能。然而,即使是使用结构
化的编程方法,一旦一个项目到达了一定的规模,其复杂度也就超过了程序员所能管理的范
围。在 20 世纪 70 年代,很多项目几乎都处于这种境地。为了解决这种问题,出现了一种
新的编程方法:面向对象编程。通过使用面向对象编程,程序员可以处理更大的,更复杂的
程序。而 C 语言是不支持这种面向对象编程方法的。于是,人们对面向对象的 C 的渴望就
直接导致了 C++的诞生。可见,自从计算机发明以来,编程的方式已经发生了巨大的变化。
最后一点,尽管 C 是世界上最受欢迎的专业编程语言之一,也有复杂的程序是 C 不能
完成的。一旦一个程序的规模达到了一定的大小,其复杂度就会增加,以至于很难从整体上
对其进行把握。C++的目的就是突破这种障碍,帮助编程人员理解并管理更大,更复杂的程
序。
C++C++C++C++的诞生
C++由 Bjarne Stroustrup 于 1979 年在位于新泽西州 Murray Hill 的贝尔实验室成功发
明。起初它的名字叫“带有类的 C”,后来在 1983 年更名为 C++。Stroustrup 在 C 的基础上
构建了 C++,因此 C++包括 C 的所有特性和优点。它还继承了 C 的理念:程序员而不是程
序掌控一切。有一点必须明确,Stroustrup 并没有创建一个全新的编程语言。相反,它增强
了已经高度成功的语言。大多数 Stroustrup 为 C 增加的特性都是为了支持面向对象的编程。
从本质上来讲,C++就是支持面向对象的 C。通过在 C 的基础上构建 C++,就实现了到面
向对象编程的平滑过渡。C 程序员不必重新学习一门新的语言,只需要学习那些新增的特性,
就能收获面向对象编程带来的好处。在设计 C++语言的时候,Stroustrup 清楚地知道在增
加支持面向对象编程的特性时,保持原有 C 的特性,包括 C 的高效,灵活和 C 的设计理念
是非常重要的。幸运的是,他的目标实现了。C++在提供了面向对象的编程优点同时,还保
留了 C 的灵活。尽管发明 C++的初衷是为了辅助管理那些大型的程序,但它绝不仅限于此。
实际上,C++的面向对象特性可以被有效地引用到实际上任何程序中。C++可以广泛地被用
来开发诸如编辑器,数据库,个人文件系统,网络工具,通信程序等,这些都非常常见。由
于 C++保留了 C 的高效性,大量的高性能系统软件都是用 C++开发的。同样,C++也经常
被用来开发 windows 程序。
C++C++C++C++的发展
C++被发明后,经过了三次大的修订,每次修订都对语言自身做了增加和改动。第一次
和第二修订分别是在 1985 年和 1990 年。第三次修订发生在 C++标准化的过程中。几年前
(现在来看,应该是十几年前了),人们开始进行 C++的标准化工作。那时,建立了由美
国国家标准研究所(ANSI)和国际标准组织(ISO)合作的标准化组织组。建议标准的第一
次草案是在 1994 年 1 月 25 日完成的。在这份草案中,ANSI/ISO 联合委员会保留了
Stroustrup 当初定义的特性,并增加了一些新的特性。总的来说,这份最初的草案反映了
当时 C++的情况。在此之后不久,发生了一件事情,促使了联合委员会大大地扩展了该标
准:由 Alexander Stepanov 提出的标准模板库的创建。标准模板库是一套我们可以用之处
理数据的通用程序的集合。通用模板库很强大,也很简洁优雅。但是它很巨大。在第一次草
案之后,委员会曾经投票来决议是否在标准 C++中增加标准模板库。标准模板库的增加使
得 C++大大超出了起初定义的范围。对标准模板库和其它一些特性的增加使得 C++标准化
的步伐减慢了许多。完全可以说 C++的标准化工作比人们期望的时间要长许多。在整个过
程中,C++中加入了许多新的特性,并做了许多小的改动。实际上,由该联合委员会制定的
C++比 Stroustrup 当初设计的 C++要复杂很多。最终的草案在 1997 年 12 月 14 日通过,
ANSI/ISO 标准 C++在 1998 年成为现实。这就是人们通常说的标准 C++。本书描述的都是
标准的 C++。本书描述的 C++是所有主流 C++编译器,包括微软的 visual C++都支持的 C++。
因此本书中的代码和信息是完全可移植的。
必备技能 1.21.21.21.2:C++C++C++C++与 JavaJavaJavaJava 和 C#C#C#C#的关系
除了 C++之外,还有两个重要的现代编程语言:Java 和 C#。Java 是有 Sun Microsystems
公司开发的,而 C#则是由微软公司开发的。由于人们有时会对 C++与 Java 和 C#的关系产
生一些混淆,这里有必要对此介绍一下。C++是 Java 和 C#之父。尽管 Java 和 C#都是在
C++的基础上对语言的特性进行了一些增加,删除和改动,但是总体上来说它们三者的语法
是几乎相同的。进一步来说,C++所采用的对象模型和 Java,C#的都是相似的。最后,三
者给人的总体感觉也是非常相近的。这就意味着,一旦学会了 C++,就能很轻易地学习 Java
和 C#。 反之亦然,如果你懂 Java 或者 C#学习 C++也是很简单的。这就是为什么 Java,
C#和 C++都是用相同的语法和对象模型了,这也是大量有经验的 C++程序员能顺地过渡到
是 Java 或者 C#的原因。它们之间的区别在于各自设计针对的计算环境不同。C++是针对指
定类型的 CPU 和操作系统而设计的高性能的语言。例如:如果你想写在 windows 操作系统
下,因特尔奔腾系列的 CPU 上运行的程序,那么 C++是最好的选择。
专家答疑
问:
Java 和 C#都实现了跨平台和可移植的编程,C++为什么不能了?
答:
Java 和 C#之所以能实现跨平台,可移植的编程,而 C++不能是因为它们的编译器生成的
目标代码不同。就 C++而言,编译器的输出是机器代码,这是 CPU 可以直接执行的。因此
它是紧密和指定的 CPU 以及操作系统相关的。如果想让 C++程序在不同的系统上运行,则
需要针对该目标系统进行代码的重新编译。为了让 C++程序可以在不同的环境上运行,就
需要生成不同的可执行版本。Java 和 C#是通过把代码编译成伪码,一种中间语言。就 Java
而言,这种伪码是在运行时系统上运行的,这就是 Java 虚拟机。对 C#而言,这就是 CLR
(公共语言运行时)。因此,Java 语言的程序可以在任何有 java 虚拟机的环境下运行,C#
的程序可以在任何实现了 CLR 的环境下运行。因为 Java 和 C#的运行时系统处于程序和
CPU 之间,和 C++相比,这就引起了多余的开销。这就是为什么,对等情况下,C++程序
比 Java 和 C#程序运行快的原因了。Java 和 C#的开发是为了满足互联网上在线程序的统
一编程需求。(C#的设计也是用来简化软件构件的开发)。互联网上连接的是许多不同的
CPU 和操作系统。因此跨平台和可移植性就成了最重要的着眼点。第一个着眼于这个问题
的语言就是 Java。Java 语言编写的程序可以在很多不同的环境下运行。因此,Java 程序
可以在互联网上自由运行。然而这样做的代价就是牺牲了效率,Java 程序的执行要比 C++
程序慢许多。同样的事情也发生在 C#身上。最终分析,如果你想开发高性能软件,就是用
C++。如果你想开发高度可移植的软件,就是用 Java 或者 C#。最后一点:请记住,C++,
java 和 C#是用来解决不同问题的。这里并没有那个语言好,那个语言不好的问题,而是那
个语言更适合用来完成我们手头工作的问题。
练习:
1. C++语言是从什么语言发展而来的?
2. C++语言产生的主要原因是什么?
3. C++语言是 Java 和 C#语言之父,对吗?
答案:
1. C++是从 C 语言发展而来的。
2. 程序复杂性的不断增加是产生 C++语言的主要原因。
3. 正确。
必备技能 1.31.31.31.3:面向对象的编程
C++的中心是围绕着面向对象的编程。正如前面介绍的那样,面向对象的编程是促进 C++
产生的主要因素。正是因为这一点,在学习编写简单的 C++程序之前,理解面向对象编程
的基本思想是非常重要的。
面向对象的编程很好地利用了结构化编程的思想,并增加了一些新的概念,能够更好地
组织程序。通常情况下,有两种方式来组织程序:以代码为中心或者以数据为中心。通过结
构化的编程技术,程序通常是以代码为中心来组织的。这种方法可以被认为是“代码作用于
数据”。
面向对象的编程则是以数据为中心。程序以数据为中心进行组织,主要的原则就是“数据
控制代码”。在面向对象的语言中,我们定义数据和允许作用于这些数据的例行程序段。因
此,数据的类型明确定义了可以作用在这些数据上的操作。
为了支持面向对象编程的原则,所有的面向对象语言,包括 C++,都有三个显著的特点:
封装,多态和继承。让我们一个一个来学习。
封装
封装是一种编程机制,它把数据和处理数据的代码捆绑在一起,这可以防止外部程序错
误地访问数据和代码。在面向对象的语言中,数据和代码可以通过黑盒子的方式绑定起来,
盒子内部是全部必要的数据和代码。当数据和代码以这种方式绑定的时候,此时我们就创建
了一个对象。换句话说,一个对象就是支持封装的设备。
专家答疑
问:
我听说过子程序段的学名为方法,那么方法和函数是同一回事情吗?
答:
通常来说,是的。方法在 Java 里面使用很广泛。C++则中叫做函数,Java 中则被称作
方法。C#程序员同样使用方法这个术语。因为它已经广泛地被采用了,所以有时候在 C++
里面,函数有时候也被称作方法。
对于一个对象来说,代码或者数据或者两者都有可能是私有的或者公有的。私有的代码
或者数据只能是该对象的其它部分可以访问和感知的。也就是说,私有的代码和或者数据是
不能被对象之外的程序段访问的。当代码或者数据是公有的,虽然它是被定义在对象中的,
但是程序的其它部分都是可以访问它的。通常情况下,对象的公有部分是用来提供对对象私
有元素的可控的访问接口的。
C++中最基本的封装单元就是类。一个类定义了对象的通用形式。它同时定义了数据和
作用于这些数据的代码。C++使用类来构建对象。对象是类的实例。因此,一个类实际上是
构建对象的工厂。
类中的数据和代码称为类的成员。更详细一点来说,成员变量,也叫做实例变量,是类
定义的数据。成员函数是作用于这些数据的操作。函数在 C++中是针对子程序的术语。
多态
多态,字面意思就是多种形态的意思。它是一种机制,可以允许一个接口来访问类的通
用动作。一个简单的多态性的例子就是汽车的方向盘。方向盘(接口)都是一样的,不管实
际中使用了怎样的转向机制。也就是说,不管你的汽车使用的是手工的转向盘,还是动力的
转向盘,或者是齿轮转向盘,方向盘的工作效果都是一样的:就是把方向盘往左转,车就会
左转,不管使用的是什么样子的转向盘。这种统一接口的好处就是一旦我们知道了如何掌控
方向盘,我们就可以开什么类型的车。
同样的原理也可以应用在编程上。比如,考虑一个栈,程序可能需要针对三种不同数据
类型的栈。一个是针对整型数的,一个是针对浮点型数据的,一个是针对字符的。在这种情
况下,栈的实现算法是一致的,只是存储的数据类型是不一样的。在非面向对象的语言中,
我们必须创建三个不同的栈的程序,每一个都是用不同的名字。然而,在 C++,通过多态,
我们就可以创建一个通用的栈,三种不同的数据类型都可以存储。这样,一旦知道了栈是如
何使用的,我们就等于知道了三种不同数据类型的栈的用法。
通常,多态的概念经常被表述如下:一个接口,多种方法。意思是说可以通过对一组相
关的活动定义一个通用的接口。多态性通过一个接口来阐明动作的通用性,可以帮助我们减
少程序的复杂性。编译器针对应用的情况来选择具体应该是那个动作(方法)。程序员不必
手工来做这种选择。我们只需要记住并使用这个通用的接口就可以了。
继承
继承是一个对象可以获取到另外一个对象的属性的过程。继承非常重要,因为它支持了
层次化的分类。仔细想想,大多数的知识都是通过层次化的分类来管理的。例如:红色的甜
苹果是属于苹果分类的,而苹果分类又是水果分类的一种,水果又是一个更大的类:食物的
一种。也就是说,食物有一些特质,比如可以食用,有营养等等,逻辑上来说它的子类水果
也是有的。除了这些特质,水果还有特殊的特质,比如多汁,香甜等等,正是这些特质使得
水果和其它的食物有所区分。苹果类定义了苹果特有的特质,比如生长在树上,非热带的等
等。一个红色香甜的苹果应该继承了它的父类的所有特质,同时也定义了一些使得它和别的
苹果区分开来的特质。
如果没有层次化的分类,每一个对象都必须显示地定义自己的所有特性。通过使用继承,
一个对象只需要定义那些使得它在整个类中显得独特的那些特质。它可以从父类那里继承所
有通用的特质。因此正是继承机制使得一个对象成为一个通用类的实例成为可能。
专家答疑
问:
文中说到面向对象的编程是一种有效的进行大程序管理的方法。但是面向对象的编程似
乎会增加相对小程序的开销。就 C++而言,这点是真是假?
答:
假。理解 C++的关键一点是使用 C++可以编写面向对象的程序,但是并不是说必须写面
向对象的程序。这一点是 C++和 Java、C#的一个很重要的不同点。Java 和 C#采用严格的
对象模型,所以每个程序,不管其多小,都是面向对象的。C++也提供了该选项。更重要的
是,在运行的时候,C++的面向对象特性是透明的,因此,如果存在的话,增加的开销也是
很少的。
练习:
1. 说出面向对象编程的原则。
2. C++中,封装的最基本的单元是什么?
3. C++中,子程序通常被称作什么?
答案:
1. 封装,多态和继承是面向对象编程的原则。
2. C++中类是封装的基本单元。
3. C++中,子程序通常被成为函数。
必备技能 1.41.41.41.4:第一个简单的程序
现在我们开始编程了。我们通过编译和运行下面的一个简短的 C++程序开始:
view plain
这是一个简单的 C++程序.
文件名称为 Sample.cpp.
1. /*
2.
3.
4. */
5. #include
using
namespace
using
namespace
using namespace
6. using
namespace std;
7. // C++程序都是从 main()函数开始的
8. intintintint main()
9. {
10.
11.
12. }
cout << "C++ is power programming.";
return
return
return
return 0;
我们将按照下面的三个步骤来进行
1.键入程序
2.编译程序
3.运行程序
在开始之前,让我们先复习两个术语:源代码和目标代码。源代码就是人类可读的程序,
它是存储在文本文件中的。目标代码是由编译器生成的程序的可执行形式。
键入程序
本书中出现的程序都可以从 Osborne 的网站上获取到:www.osborne.com 。然而,如
果你想手工键入这些程序也是可以的。手工键入这些程序通常可以帮助我们记忆这些关键的
概念。如果你选择手工键入这些程序,你必须有一个文本编辑器,而不是一个字处理器。字
处理器通常存储带有格式的文本信息。这些信息会使得 C++编译器不能正常工作。如果你
使用的是 windows 平台,那么你可以使用记事本程序,或者其它你喜欢的程序编辑器。
存储源代码的文件名称从技术上来说是可以任意取的。然而,C++程序文件通常采用.cpp
的扩展名。因此,你可以任意命名 C++的程序文件,但是它的扩展名应该是.cpp。针对这里
的第一个例子,源文件取名为 Sample.cpp。本书中的其它程序,你可以自行选择文件名。
编译程序
怎样编译 Sample.cpp 取决于你的编译器和你采用了什么样子的编译选项。更进一步来
说,许多编译器,例如你可以自由下载的微软的 Visual C++ Express Edition,都提供两种
不同的编译方式:命令行编译和集成开发环境。因此,这里不可能给出一个通用的编译 C++
程序的操作。你必须查看与你的编译器相关的操作指南。
如果你采用的是 Visual C++,那么最简单的编译和运行本书中的程序的方式就是采用 VC 中
提供的命令行。例如,使用 Visual C++来编译 Sampler.cpp,你可以采用这样的命令行:
C:/...>cl -GX Sample.cpp
其中-GX 是增强编译选项。在使用 Visual C++命令行编译器之前,你必须先执行 visual C++
提供的批处理文件 VCVARS32.BAT。Visual Studio 同时也提供了一个很方便使用命令行
的方式:可以通过任务栏的 开始|程序|Microsoft Visual Studio 菜单中的工具列表中的
Visual Studio Command Prompt 菜单来激活命令行。