第一章.
让自己适应
C++
无论你有怎样的编程背景,都需要用一些时间和精力来适应
C++
。
C++
是一门强大的编程语言,它拥有数不尽的实用功能,但是在你能够熟练地驾御
C++
的力量,并且恰当而高效地利用这些功能之前,首先你要适应
C++
做事情的方式。这本书自始至终都是在介绍如何顺利地完成这一适应过程,但是相比较大多数议题而言,还有一些更为基础的内容,本章向大家介绍的就是这些更为基础的东西。
第1项:
把
C++
看作多种语言的联合体
起初,
C++
仅仅是增补了面向对象特性的
C
语言。甚至
C++
原始的名称都叫做
“
使用类的
C
语言
”
,这可以很明显地反映出这一继承关系。
随着
C++
逐渐成熟,它变得更加丰富多彩,更加大胆前卫,它开始采纳一些与
“
使用类的
C
语言
”
不同的编程策略。在构建函数时为达到不同目标,
C++
的发明者为其添加了异常处理机制(参见第
29
项);模板为设计思想注入了新的活力(参见第
41
项);同时,
STL
使
C++
达到了前所未有的可扩展度。
今天的
C++
是一门多范型编程语言,它包含面向过程、面向对象、函数式编程、泛型、元编程等等特征。
C++
的强大和灵活几乎是无可比拟的,但这也会造成一些紊乱。所有的
“
恰当的用法
”
的准则似乎都存在例外。那么我们如何恰当的理解它呢?
最简单的办法就是把
C++
看作一个有若干门语言组成的联合体,而不是一门单独的语言。在一个特定的子语言中,规则就显得简单、直接,而且不易忘记。当你更换到另一门子语言时,规则就相应地改变了。为了理解
C++
,你必须认清
C++
主要的子语言。幸运的是,主要的子语言只有四门:
l
C
。尽管变革是深刻的,
C++
仍然基于
C
语言。程序块、语句、预处理器、内建数据类型、数组、指针,等等。所有都来自于
C
。在许多情况下,
C++
可以比
C
更优雅地完成一些任务(比如第
2
项(预处理器的替代方法)和第
13
项(使用对象管理资源)),但是当你发现你正在使用
“
C++
中的
C
”
这一部分编写程序时,高效编程原则就会反映出
C
语言的局限:没有模板、没有异常处理、没有重载,等等。
l
面向对象的
C++
。这一部分的
C++
就是
“
使用类的
C
语言
”
的一切:类(包括构造器和析构器)、封装、继承、多态、虚函数(动态绑定),等等。这一部分的
C++
是面向对象设计最为直接的应用,即类的规则。
l
包含模板的
C++
。这是
C++
中泛型编程的一部分,大多数程序员在泛型编程领域涉足甚浅。模板的概念对
C++
产生了深远的影响,将模板的使用在编程规则里单列一章也不为过(比如,第
46
项中介绍的通过调用模板函数简化类型转换)。模板如此之强大,它足以为我们带来了一个全新的编程范型:模板元编程
(template meta-programming,
简称
TMP)
。第
48
项是对
TMP
的一个简介,但是除非你对模板到了痴迷的地步,你大可不必投入过多精力。主流
C++
编程很少涉及到
TMP
规则。
l
STL
。显然地,
STL
是一个模板库,但是它是一个非常特别的模板库。它的约定使得容器、迭代器、算法、函数对象完美地协同工作,当然模板和库也可以基于其它的理念来构建。
STL
有自己独特的解决问题的方法,当你使用
STL
编程时,你必须要遵循它的约定。
时刻地对这四门子语言保持头脑清醒,当高效规则要求你必须要更改策略,从而必须更改到另一门子语言时,不要大惊小怪。比如说,对内建(比如类似
C
语言的)类型而言,传值要比通过引用传递更高效,但是当你从
“
C++
中的
C
”
迁移到
“
面向对象的
C++
”
后,构造器和析构器的存在就意味着通过引用传递给一个
const
常量会更好。在使用
“
包含模板的
C++”
时通常都是这样的状况,因为你也许根本就不知道当前正在处理的对象的类型。然而当开始使用
STL
时,迭代器和函数对象都是模仿
C
语言中指针的机制,在
STL
的迭代器和函数对象上,
C
语言的传值规则又再次奏效了。(关于如何在各种传参方法中找出最合适的将在第
20
项中介绍。)
C++
并不是一门单一的编程语言,它不仅仅拥有一套单一的规则,而是四门子语言的联合体,每门子语言都有自己的惯例。时刻清醒地分辨这四门子语言,你会发现
C++
并没有那么难。
需要记住的
l
C++
的高效编程规则根据你正在使用的
C++
的那一部分而改变。