C++编程思想.docx

上传人:b****7 文档编号:11156170 上传时间:2023-02-25 格式:DOCX 页数:52 大小:51.63KB
下载 相关 举报
C++编程思想.docx_第1页
第1页 / 共52页
C++编程思想.docx_第2页
第2页 / 共52页
C++编程思想.docx_第3页
第3页 / 共52页
C++编程思想.docx_第4页
第4页 / 共52页
C++编程思想.docx_第5页
第5页 / 共52页
点击查看更多>>
下载资源
资源描述

C++编程思想.docx

《C++编程思想.docx》由会员分享,可在线阅读,更多相关《C++编程思想.docx(52页珍藏版)》请在冰豆网上搜索。

C++编程思想.docx

C++编程思想

下载

第1章对象的演化

计算机革命起源于一台机器,程序设计语言也源于一台机器。

然而计算机并不仅仅是一台机器,它是心智放大器和另一种有表述能力的媒体。

这一点

使它不很像机器,而更像我们大脑的一部分,更像其他有表述能力的手段,例如写作、绘画、

雕刻、动画制作或电影制作。

面向对象的程序设计是计算机向有表述能力的媒体发展中的一

部分。

本章将介绍面向对象程序设计(OOP)的基本概念,然后讨论OOP开发方法,最后介绍使

程序员、项目和公司使用面向对象程序设计方法而采用的策略。

本章是一些背景材料,如果读者急于学习这门语言的具体内容,可以跳到第2章,然后再

回过头来学习本章。

1.1基本概念

C++包含了比面向对象程序设计基本概念更多的内容,读者应当在学习设计和开发程序之

前先理解该语言所包含的基本概念。

1.1.1对象:

特性+行为[1]

第一个面向对象的程序设计语言是60年代开发的Simula-67。

其目的是为了解决模拟问题。

典型的模拟问题是银行出纳业务,包括出纳部门、顾客、业务、货币的单位等大量的“对象”。

把那些在程序执行期间除了状态之外其他方面都一样的对象归在一起,构成对象的“类”,这

就是“类”一词的来源。

类描述了一组有相同特性(数据元素)和相同行为(函数)的对象。

类实际上就是数据类

型,例如,浮点数也有一组特性和行为。

区别在于程序员定义类是为了与具体问题相适应,而

不是被迫使用已存在的数据类型。

这些已存在的数据类型的设计动机仅仅是为了描述机器的存

储单元。

程序员可以通过增添他所需要的新数据类型来扩展这个程序设计语言。

该程序设计系

统欢迎创建、关注新的类,对它们进行与内部类型一样的类型检查。

这种方法并不限于去模拟具体问题。

尽管不是所有的人都同意,但大部分人相信,任何程

序都模拟所设计系统。

OOP技术能很容易地将大量问题归纳成为一个简单的解,这一发现产生

了大量的OOP语言,其中最著名的是Smalltalk—C++之前最成功的OOP语言。

抽象数据类型的创建是面向对象程序设计中的一个基本概念。

抽象数据类型几乎能像内部类

型一样准确工作。

程序员可以创建类型的变量(在面向对象程序设计中称为“对象”或“实例”)

并操纵这些变量(称为发送“消息”或“请求”,对象根据发来的消息知道需要做什么事情)。

1.1.2继承:

类型关系

类型不仅仅说明一组对象上的约束,还说明与其他类型之间的关系。

两个类型可以有共同

的特性和行为,但是,一个类型可能包括比另一个类型更多的特性,也可以处理更多的消息

[1]这一描述部分引自我对《TheTaoofObjects》(GaryEntsminger著)一书的介绍。

(或对消息进行不同的处理)。

继承表示了基本类型和派生类型之间的相似性。

一个基本类型具

有所有由它派生出来的类型所共有的特性和行为。

程序员创建一个基本类型以描述系统中一些

对象的思想核心。

由这个基本类型派生出其他类型,表达了认识该核心的不同途径。

例如,垃圾再生机要对垃圾进行分类。

这里基本类型是“垃圾”,每件垃圾有重量、价值

等等,并且可以被破碎、融化或分解。

这样,可以派生出更特殊的垃圾类型,它们可以有另外

的特性(瓶子有颜色)或行为(铝可以被压碎,钢可以被磁化)。

另外,有些行为可以不同

(纸的价值取决于它的种类和状态)。

程序员可以用继承建立类的层次结构,在该层次结构中用

类型术语来表述他需要解决的问题。

第二个例子是经典的形体问题,可以用于计算机辅助设计系统或游戏模拟中。

这里基本类

型是“形体”,每个形体有大小、颜色、位置等。

每个形体能被绘制、擦除、移动、着色等。

由此,可以派生出特殊类型的形体:

圆、正方形、三角形等,它们中的每一个都有另外的特性

和行为,例如,某些形体可以翻转。

有些行为可以不同(计算形体的面积)。

类型层次结构既

体现了形体间的类似,又体现了它们之间的区别。

用与问题相同的术语描述问题的解是非常有益的,这样,从问题描述到解的描述之间就不

需要很多中间模型(程序语言解决大型问题,就需要中间模型)。

面向对象之前的语言,描述

问题的解不可避免地要用计算机术语。

使用对象术语,类型层次结构是主要模型,所以可以从

现实世界中的系统描述直接进入代码中的系统描述。

实际上,使用面向对象设计,人们的困难

之一是从开始到结束过于简单。

一个已经习惯于寻找复杂解的、训练有素的头脑,往往会被问

题的简单性难住。

1.1.3多态性

当处理类型层次结构时,程序员常常希望不把对象看作是某一特殊类型的成员,而把它看

作基本类型成员,这样就可以编写不依赖于特殊类型的代码。

在形体例子中,函数可以对一般

形体进行操作,而不关心它们是圆、正方形还是三角形。

所有的形体都能被绘制、擦除和移动,

所以这些函数能简单地发送消息给一个形体对象,而不考虑这个对象如何处理这个消息。

这样,新添类型不影响原来的代码,这是扩展面向对象程序以处理新情况的最普通的方法。

例如,可以派生出形体的一个新的子类,称为五边形,而不必修改那些处理一般形体的函数。

通过派生新子类,很容易扩展程序,这个能力很重要,因为它极大地减少了软件维护的花费。

(所谓“软件危机”正是由软件的实际花费远远超出人们的想象而产生的。

如果试图把派生类型的对象看作它们的基本类型(圆看作形体,自行车看作车辆,鸬鹚看作

鸟),就有一个问题:

如果一个函数告诉一个一般形体去绘制它自己,或者告诉一个一般的车辆去

行驶,或者告诉一只一般的鸟去飞,则编译器在编译时就不能确切地知道应当执行哪段代码。

样的问题是,消息发送时,程序员并不想知道将执行哪段代码。

绘图函数能等同地应用于圆、正

方形或三角形,对象根据它的特殊类型来执行合适的代码。

如果增加一个新的子类,不用修改函

数调用,就可以执行不同的代码。

编译器不能确切地知道执行哪段代码,那么它应该怎么办呢?

在面向对象的程序设计中,答案是巧妙的。

编译器并不做传统意义上的函数调用。

由非

OOP编译器产生的函数调用会引起与被调用代码的“早捆绑”,对于这一术语,读者可能还没

有听说过,因为从来没有想到过它。

早捆绑意味着编译器对特定的函数名产生调用,而连接器

确定调用执行代码的绝对地址。

对于OOP,在程序运行之前,编译器不确定执行代码的地址,

所以,当消息发送给一般对象时,需要采用其他的方案。

为了解决这一问题,面向对象语言采用“晚捆绑”的思想。

当给对象发送消息时,在程序

2C++编程思想

下载

运行之前不去确定被调用的代码。

编译器保证这个被调用的函数存在,并完成参数和返回值的

类型检查,但是它不知道将执行的准确代码。

为了实现晚捆绑,编译器在真正调用的地方插入一段特殊的二进制代码。

通过使用存放在

对象自身中的信息,这段代码在运行时计算被调用函数的地址(这一问题将在第14章中详细介

绍)。

这样,每个对象就能根据一个指针的内容有不同的行为。

当一个对象接收到消息时,它

根据这个消息判断应当做什么。

程序员可以用关键字virtual表明他希望某个函数有晚捆绑的灵活性,而并不需要懂得

virtual的使用机制。

没有它,就不能用C++做面向对象的程序设计。

Virtual函数(虚函数)表

示允许在相同家族中的类有不同的行为。

这些不同是引起多态行为的原因。

1.1.4操作概念:

OOP程序像什么

我们已经知道,用C语言编写的过程程序就是一些数据定义和函数调用。

要理解这种程序

的含义,程序员必须掌握函数调用和函数实现的本身。

这就是过程程序需要中间表示的原因。

中间表示容易引起混淆,因为中间表示的表述是原始的,更偏向于计算机,而不偏向于所解决

的问题。

因为C++向C语言增加了许多新概念,所以程序员很自然地认为,C++程序中的main()会

比功能相同的C程序更复杂。

但令人吃惊的是,一个写得很好的C++程序一般要比功能相同的

C程序更简单和容易理解。

程序员只会看到一些描述问题空间对象的定义(而不是计算机的描

述),发送给这些对象的消息。

这些消息表示了在这个空间的活动。

面向对象程序设计的优点

之一是通过阅读,很容易理解代码。

通常,面向对象程序需要较少的代码,因为问题中的许多

部分都可以用已存在的库代码。

1.2为什么C++会成功

C++能够如此成功,部分原因是它的目标不只是为了将C语言转变成OOP语言(虽然这是

最初的目的),而且还为了解决当今程序员,特别是那些在C语言中已经大量投资的程序员所

面临的许多问题。

人们已经对OOP语言有了这样传统的看法:

程序员应当抛弃所知道的每件事

情并且从一组新概念和新文法重新开始,他应当相信,最好丢掉所有来自过程语言的老行装。

从长远角度看,这是对的。

但从短期角度看,这些行装还是有价值的。

最有价值的可能不是那

些已存在的代码库(给出合适的工具,可以转变它),而是已存在的头脑库。

作为一个职业C

程序员,如果让他丢掉他知道的关于C的每一件事,以适应新的语言,那么,几个月内,他将

毫无成果,直到他的头脑适应了这一新范例为止。

如果他能调整已有的C知识,并在这个基础

上扩展,那么他就可以继续保持高效率,带着已有的知识,进入面向对象程序设计的世界。

为每个人有他自己的程序设计模型,所以这个转变是很混乱的。

因此,C++成功的原因是经济

上的:

转变到OOP需要代价,而转变到C++所花的代价较小。

C++的目的是提高效率。

效率取决于很多东西,而语言是为了尽可能地帮助使用者,尽可

能不用武断的规则或特殊的性能妨碍使用者。

C++成功是因为它立足于实际:

尽可能地为程序

员提供最大便利。

1.2.1较好的C

即便程序员在C++环境下继续写C代码,也能直接得到好处,因为C++堵塞了C语言中的一

第1章对象的演化3

下载

些漏洞,并提供更好的类型检查和编译时的分析。

程序员必须先说明函数,使编译器能检查它

们的使用情况。

预处理器虚拟删除值替换和宏,这就减少了查找疵点的困难。

C++有一个性能,

称为references(引用),它允许对函数参数和返回值的地址进行更方便的处理。

函数重载改进了

对名字的处理,使程序员能对不同的函数使用相同的名字。

另外,名字空间也加强了名字的控

制。

许多性能使C的更安全。

1.2.2采用渐进的学习方式

与学习新语言有关的问题是效率的问题。

所有公司都不可避免地因软件工程师学习新语言

而突然降低了效率。

C++是对C的扩充,而不是新的文法和新的程序设计模型。

程序员学习和

理解这些性能,逐渐应用并继续创建有用的代码。

这是C++成功的最重要的原因之一。

另外,已有的C代码在C++中仍然是有用的,但因为C++编译器更严格,所以,重新编译

这些代码时,常常会发现隐藏的错误。

1.2.3运行效率

有时,以程序执行速度换取程序员的效率是值得的。

假如一个金融模型仅在短期内有用,

那么快速创建这个模型比所写程序能更快速执行重要。

很多应用程序都要求有一定的运行效率,

所以C++在更高运行效率时总是犯错。

C程序员非常重视运行效率,这让他们认为这个语言不

太庞大,也不太慢。

产生的代码运行效率不够时,程序员可以用C++的一些性能做一些调整。

C++不仅有与C相同的基本控制能力(和C++程序中直接写汇编语言的能力),非正式的证

据指出,面向对象的C++程序的速度与用C写的程序速度相差在±10%之内,而且常常更接近。

用OOP方法设计的程序可能比C的对应版本更有效。

1.2.4系统更容易表达和理解

为适合于某问题而设计的类当然能更好地表达这个问题。

这意味着写代码时,程序员是在

用问题空间的术语描述问题的解(例如“把锁链放在箱子里”),而不是用计算机的术语,也就

是解空间的术语,描述问题的解(例如“设置芯片的一位即合上继电器”)。

程序员所涉及的是

较高层的概念,一行代码能做更多的事情。

易于表达所带来的另一个好处是易于维护。

据报道,在程序的整个生命周期中,维护占了

花费的很大部分。

如果程序容易理解,那么它就更容易维护,还能减少创建和维护文档的花

费。

1.2.5“库”使你事半功倍

创建程序的最快方法是使用已经写好的代码:

库。

C++的主要目标是让程序员能更容易地

使用库,这是通过将库转换为新数据类型(类)来完成的。

引入一个库,就是向该语言增加一

个新类型。

编译器负责这个库如何使用,保证适当的初始化和清除,保证函数被正确地调用,

因此程序员的精力可以集中在他想要这个库做什么,而不是如何做上。

因为程序的各部分之间名字是隔离的,所以程序员想用多少库就用多少库,不会有像C语

言那样的名字冲突。

?

模板的源代码重用

一些重要的类型要求修改源代码以便有效地重用。

模板可以自动完成对代码的修改,因而

4C++编程思想

下载

是重用库代码特别有用的工具。

用模板设计的类型很容易与其他类型一起工作。

因为模板对程

序员隐藏了这类代码重用的复杂性,所以特别好用。

1.2.6错误处理

在C语言中,错误处理声名狼藉。

程序员常常忽视它们,对它们束手无策。

如果正在建大

而复杂的程序,没有什么比让错误隐藏在某处,且不能指出它来自何处更糟的了。

C++的异常

处理(见第17章的内容)保证能检查到错误并进行处理。

1.2.7大程序设计

许多传统语言对程序的规模和复杂性有自身的限制。

例如,BASIC对于某些类型的问题能

很快解决,但是如果这个程序有几页纸长,或者超出该语言的正常解题范围,那么它可能永远

算不出结果。

C语言同样有这样的限制,例如当程序超过50000行时,名字冲突就开始成为问

题。

简言之,程序员用光了函数和变量名。

另一个特别糟糕的问题是如果C语言中存在一些小

漏洞—错误藏在大程序中,要找出它们是极其困难的。

没有清楚的文字告诉程序员,什么时候他的语言会失效,即便有,他也会忽视它们。

他不

说“我的BASIC程序太大,我必须用C重写”,而是试图硬塞进另外几行,增加额外的性能。

所以额外的花费就悄悄增加了。

设计C++的目的是为了辅助大程序设计,也就是说,去掉小程序和大程序之间复杂性的分

界。

当程序员写hello-world类实用程序时,他确实不需要用OOP、模板、名字空间和异常处理,

但当他需要的时候,这些性能就有用了。

而且,编译器在排除错误方面,对于小程序和大程序

一样有效。

1.3方法学介绍

所谓方法学是指一组过程和启发式,用以减少程序设计问题的复杂性。

在OOP中,方法学

是一个有许多实践的领域。

因此,在程序员考虑采用某一方法之前,了解该方法将要解决的问

题是很重要的。

对于C++,有一点是确实的:

它本身就是希望减少程序表达的复杂性。

从而不

必用更复杂方法学。

对于用过程语言的简单方法所不能处理的大型问题,在C++中用一些简单

的方法就足够了。

认识到“方法学”一词含义太广是很重要的。

实际上,设计和编写程序时,无论做什么都

在使用一种方法。

只不过因为它是程序员自己的方法而没有意识到。

但是,它是程序员编程中

的一个过程。

如果过程是有效的,只需要用C++做很小的调整。

如果程序员对他的效率和调整

程序的方法不满意,他可以考虑采用一种更正式的方法。

1.3.1复杂性

为了分析复杂性,先假设:

程序设计制定原则来对付复杂性。

原则以两种方式出现,每种方式都被单独检查。

1)内部原则体现在程序自身的结构中,机灵而有见解的程序员可以通过程序设计语言的表

达方式了解这种内部原则。

2)外部原则体现在程序的源信息中,一般被描述为“设计文档”(不要与产品文档混淆)。

我认为,这两种形式的原则互相不一致:

一个是程序的本质,是为了让程序能工作而产生

第1章对象的演化5

下载

的,另一个是程序的分析,为了将来理解和维护程序而产生的。

创建和维护都是程序生命期的

基本组成部分。

有用的程序设计方法把两者综合为最合适的方式,而不偏向任何一方。

1.3.2内部原则

程序设计的演化(C++只是其中的一步)从程序设计模型强加于内部开始,也就是允许程

序员为内存位置和机器指令取别名。

这是数字机器程序设计的一次飞跃,带动了其他方面的发

展,包括从初级机器中抽象出来,向更方便地解决手边问题的模型发展。

不是所有这些发展都

能流行,起源于学术界并延伸进计算机世界的思想常常依赖于所适应的问题。

命名子程序的创建和支持子程序库的连接技术在50年代向前飞跃发展,并且孕育出了两个

语言,它们在当时产生了巨大冲击,这就是为科学工作者使用的FORTRAN(FORmula-

TRANslation)和为商业者使用的COBOL(COmmonBusiness-OrientedLanguage)。

纯计算机

科学中很成功的语言是Lisp(List-Processing),而面向数学的语言应当是APL(AProgramming

Language)。

这些语言的共同特点是对过程的使用。

Lisp和APL的创造专注于语言的高雅—语言的

“mission语句”嵌入在处理所有任务情况的引擎中。

FORTRAN和COBOL的创造是为了解决专

门的问题,当这些问题变得更复杂,有新的问题出现时,它们又得到了发展。

甚至它们进入衰

退期后,仍在发展:

FORTRAN和COBOL的版本都面向对象进行了扩充(后时髦哲学的基本原

则是:

任何具有自己独特生活方式的组织,其主要目标就是使这种生活方式永存)。

命名子程序在程序设计中起了重要作用,语言的设计围绕着这一原则,特别是Algol和

Pascal。

同时另外一些语言也出现了,它们成功地解决了程序设计的一些子集问题,并将它们

有序排列。

最有趣的两个语言是Prolog和FORTH。

前者是围绕着推理机而建立的(在其他语言

中常常称作库)。

后者是一个可扩充语言,允许程序员重新形成这个语言,以适应所解决的问

题,观念上类似于面向对象程序设计。

FORTH还可以改变语言,因而很难维护,并且是内部

原则概念最纯正的表达,它强调的是问题一时的解,而不是对这个解的维护。

人们还创造了其他许多语言,以解决某一部分的程序设计问题。

通常,这些语言以特定的

目标开始。

例如,BASIC(BeginnersAll-purposeSymbolicInstructionCode)是在60年代设计

的,目的是使程序设计对初学者更简单。

APL的设计是为了数学处理。

两种语言都能够解决其

他问题,而关键在于它们是否是这些问题集合最理想的解。

有一句笑话是,“带着锤子三年,

看什么都是钉子”。

这反映了根本的经济学真理:

如果我们只有BASIC或APL语言,特别是,

当最终期限很短且这个解的生命期有限时,它就是我们问题最好的解。

然而,最终考虑两个因素:

复杂性的管理和维护(将在下一部分讨论)。

即这种语言首先

是为某一领域开发的,而程序员又不愿花很长时间来熟悉这门语言,其结果只能使程序越来越

长,使手头的问题屈服于语言。

界限是模糊的:

谁能说什么时候您的语言会使您失望呢?

这不

是马上就出现的。

问题的解开始变长,并且对于程序员更具挑战性。

为了知道语言大概的限制,你得更聪明,

这种聪明变成了一种标准,也就是“为了使该语言工作而努力”。

这似乎是人类的操作方式,

而不是遇到缺陷就抱怨,并且不再称它为缺陷。

最终,程序设计问题对于求解和维护变得太困难了,即求得的解太昂贵了。

人们最终明白

了,程序的复杂性超出了我们能够处理的程度。

尽管一大类程序设计要求开发期间去做大部分

工作并创建要求最小维护的解(或者简单地丢掉这个解,或者用不同的解替换它),但这只是

问题的一部分。

一般情况是,我们把软件看作是为人们提供服务的工具。

如果用户的需要变化

6C++编程思想

下载

了,服务就必须随着变化。

这样,当第一版本开始运行时,项目并没有结束。

项目是一个不断

进化的生命体。

程序的更新变成了一般程序设计问题的一个部分。

1.3.3外部原则

为了更新和改善程序,需要更新思考问题的方法。

它不只是“我们如何让程序工作”,而

是“我们如何让程序工作并且使它容易改变”。

这里就有一个新问题:

当我们只是试图让程序

工作时,我们可以假设开发组是稳定的(总之,我们可以希望这样),但是,如果我们正在考

虑程序的整个生命期,就必须假设开发组成员会改变。

这意味着,新组员必须以某种方式学习

原程序的要点,并与老组员互相通讯(也许通过对话)。

这样,该程序就需要某种形式的设计

文档。

因为只想让程序工作,文档并不是必需的,所以还没有像由程序设计语言强加于程序那样

的、强加于创建文档的规则。

这样,如果要求文档满足特定的需要,就必须对文档强加外部原

则。

文档是否“工作”,这很难确定(并且需要在程序一生中验证),因此,对外部原则“最好”

形式的争论.比对“最好”程序设计语言的争论更激烈。

决定外部原则时,头脑中的重要问题是“我准备解决什么问题”。

问题的根本就是上面所

说的“我们如何让它工作和使它容易改变”。

然而,这个问题常常有多种解释:

它变成了“我

如何才能与FoobleBlah文档规范说明一致,以使政府会为此给我拨款”。

这样,外部原则的目

的是为了建立文档,而不是为了设计好的、可维护的程序。

文档竟然变得比程序本身更重要

了。

被问到未来一般和特殊的计算的方向时,我会从这样的问题开始:

哪种解花费较少?

假设

这个解满足需要,价格的不同足以使程序员放弃他当前做事情的习惯方式吗?

如果他的方法包

括存储在项目分析和设计过程中所创建的每个文档,并且包括当项目进化时维护这些文档,那

么当项目更新时,他的系统将花费很大,但是它能使新组员容易理解(假设没有那么多的使人

害怕阅读的文档)。

这样创建和维护方法的花费会和它打算替代方法的花费一样多。

外部结构系列的另一个极端是最小化方法。

为完成设计而进行足够的分析,然后丢掉它们,

使得程序员不再花时间和钱去维护它;为开始编码而做足够的设计,然后丢掉这个设计,使得

程序员不再花时间和钱去维护这些文档;然后使得代码是一流的和清晰的,代码中只需要最少

的注释。

为了使新组员快速参与项目,代码连同注释就足够了。

因为在所有这些乏味的文档上,

新组员只需花费很少的时间(总之,没有人真地理解它们),所以他能较快地参与工作。

即便不维护文档,丢掉文档也不是最好的办法,因为这毕竟是程序员所做的有效工作。

些形式的文档通常是必须的(参看本章后面的描述)。

1.通讯

对于较大的项目,期望代码像文档一样充分是不合理的,尽管我们在实际中常常这样期望。

但是,代码包含了我们实际上希望外部原则所产生的事物的本质:

通讯。

我们只是希望能与改

进这个程序的新组员通讯就足够了。

但是,我们还想使花费在外部原则上的钱最少,因为最终

人们只为这个程序所提供的服务付钱,而不是为它后面的设计文档付钱。

为了真正有用,外部

原则应当做比只产生文档更多的事情—它应当是项目组成员在创建设计时为了讨论问题而采

用的通讯方法。

理想的外部原则目标是使关于程序分析和设计的通讯更容易。

这对于现在为这

个程序而工作的人们和将来为这个程序而工作的人们是有帮助的。

中心问

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1