C++语言风格流变史

来源:互联网  作者:王咏刚
摘要:程序代码也有风格,这算不得什么新鲜事。早在20世纪80年代,C语言程序员就必须在K&R风格和ANSI风格之间择善而从。但平心而论,我确实没有见过哪一种语言能像C++这样,在代码风格方面表现得如此诡谲和难以捉摸:谁也说不清C++代码究竟能衍生出多少种迥异…

4. 模板——现代C++风格的基础

Stroustrup于1988年首次公布了与模板(template)有关的语法设计。毫无疑问,这是一项对现代C++的语言风格影响最大的技术改进。模板的概念来自Clu语言,并综合了Smalltalk和Ada语言中相关技术的优点。1991年后,包含模板机制的开发环境(DEC C++、IBM C++、Borland C++等)陆续问世。但直到1995年STL(Standard Template Library)模板库逐渐发展成熟以后,模板技术才在程序员中迅速普及开来。

下面的例子取自SGI STL的示例代码,它基本反映了使用模板技术后C++代码的整体风格:

template <class InputIterator, class T>
InputIterator find(InputIterator first,
  InputIterator last, const T& value)
{
  while (first != last && *first != value)
      ++first;
  return first;
}

在这样的C++代码中,除了少数几个关键字和操作符以外,我们几乎找不到多少C语言的痕迹了。模板技术兼顾了类型安全和编码灵活性的双重需求,但它同时也为C++语言引入了一种更加精妙但也较难理解(相对于没有模板的代码而言)的代码风格。许多传统的C语言拥护者讨厌这种风格的代码,但更多的新生代程序员对其钟爱有加。1998年,在ANSI/ISO标准化委员会的支持下,STL被作为标准C++库(Standard C++ Library)的一部分收入了C++国际标准之中。今天,以模板、异常等现代C++技术为代表的语言风格也已在事实上成为了C++世界的“官方风格”。

5. ATL——COM时代的另类C++

除了STL模板库之外,还有一个与模板风格相关的例子。下面的代码片断取自Visual C++自动生成的ATL控件工程:

class ATL_NO_VTABLE CMyATLObj :
  public IMyATLObj,
  public IpersistStreamInitImpl
      <CMyATLObj>,
  public IOleControlImpl<CMyATLObj>,
  public IOleObjectImpl<CMyATLObj>,
  public IoleInPlaceActiveObjectImpl
      <CMyATLObj>,
  public IViewObjectExImpl<CMyATLObj>,
  public IoleInPlaceObjectWindowlessImpl
      <CMyATLObj>,
  public IPersistStorageImpl<CMyATLObj>,
  public IspecifyPropertyPagesImpl
      <CMyATLObj>,
  public IQuickActivateImpl<CMyATLObj>,
  public IDataObjectImpl<CMyATLObj>,
  public IProvideClassInfo2Impl
      <&__uuidof(CMyATLObj), NULL>,
  public CComControl<CMyATLObj>
......

注意控件类CMyATLObj的代码,CMyATLObj类居然是从N个接口类和控件类中派生出来的,类的声明语句中随处可见模板的身影——这就是Microsoft为我们设计的别具一格的ATL风格的代码了。之所以要不惜代价地大量使用模板、多重继承等语言特性,这主要为了适应COM、OLE、ActiveX等在架构上本来就相对复杂的技术体系。但这样一来,使用ATL的代码在所有C++代码中,就拥有了一副异乎寻常的长相了:到处都是尖括号,到处都是以“I”打头的标识符,甚至还有多重尖括号的嵌套……如果要求一个刚学会C++语言的程序员立刻读懂一大段ATL代码,我想,用不了几分钟,他就会被代码中那些晦涩、离奇的语言风格折磨得精神崩溃了。

6. 标准C++——一种全新的语言?

C++语言的标准化进程远远落后于语言本身的普及速度。1990年以后,ANSI/ISO的C++标准化委员会才将包括Stroustrup在内的大批专家以及包括Apple、Borland、DEC、HP、IBM、Microsoft、Sun、Unisys在内的知名公司召集在一起,像所有国家的议会或人民代表大会一样通过没完没了的会议、讨论和投票制定C++的国际标准。标准直到1998年9月才正式发布。在国际标准化组织的档案库里,C++标准的代号是ISO/IEC 14882:1998。

Stroustrup建议我们把标准C++当作一种全新的语言来学习[3]。这一说法显然是基于这样一个事实:标准C++语言已经拥有了一种稳定的、可以推广的语言风格,即,通过对STL等既有技术的肯定,ANSI/ISO委员会在1998年的标准中正式认可了包括模板、容器类、I/O流库、异常处理等典型语言特征的现代C++风格。风格的稳定意味着语言本身的进步和成熟,也意味着程序员们对C++的认识必须上升到一个新的层次——那些至今还在编写仅由类和C语言库函数组成的C++代码的程序员,一定会成为Stroustrup及其同仁们的取笑对象的。

Stroustrup的《C++程序设计语言》第3版对标准C++风格做了最权威的阐释。在Stroustrup等专家学者的号召下,越来越多的项目开始编写符合标准C++风格的代码。这一点在许多开放源代码的项目中体现得特别明显。这多半是由于,使用C++语言的开源项目大多都不会像大企业里的项目组那样,在语言风格上会受到公司背景或历史习惯的羁绊。在具体的编程实践中,开源项目的程序员们一方面可以坚决地贯彻标准C++的语言风格,另一方面也可以根据自己的喜好为代码增添一些感情色彩。例如,在OpenOffice的源码中,标识符的前缀规范就相当有特点,连指针和引用类型的变量都由不同的前缀字母区分;下面给出的Linux桌面管理器KDE 3.1.4的源代码片断则显示出,开发KDE的程序员在代码风格上或多或少受到了Java语言风格的影响:

class delUser: public KDialogBase {
  Q_OBJECT
public:
  delUser(KUser *AUser, QWidget *parent = 0,
   const char *name = 0);
  bool getDeleteHomeDir()
   { return m_deleteHomeDir->isChecked(); }
  bool getDeleteMailBox()
   { return m_deleteMailBox->isChecked(); }
private:
  QCheckBox *m_deleteHomeDir;
  QCheckBox *m_deleteMailBox;
};

7. 读不懂的代码——兼容并包的语言风格

说到标准C++语言风格,有必要给大家看一段非常古怪但也非常有趣的代码。你看得懂下面这段C++代码吗?它是真正的C++代码吗?

%:include <iostream>
using namespace std;
%:define MAX 5
void main()
<%
  int m<:MAX:>;
  int i = 1;
  for (i = 0; i < MAX; i++)
  <%
      m<:i:> = i;
      if (i not_eq 3 and i < 5)
          cout << i << endl;
  %>
%>

这是我自己编写的一段代码。你也许无法在Visual C++环境下运行它,但它的语法的确符合1998年C++标准的规定。在GNU C++环境下,我曾成功地将其编译为可执行程序。

简单说来,这段风格诡异的C++代码其实是根据C++标准中关于可替换标记(Alternative Tokens)的规定而编写的。该规定的设计初衷是要适应欧洲某些国家的标准字符集缺少“{”、“#”等标点符号(特别是在一些传统的终端设备上)的现状。严格地讲,这算不得一种真正的语言风格,但类似的规定的确体现了ANSI/ISO委员会在语言设计上兼容并包的宽广胸襟。

【相关文章】好搜一下
修练8年:C++面向对象程序设计之体会

修练8年:C++面向对象程序设计之体会

六年前,我刚热恋“面向对象”(Object-Oriented)时,一口气记住了近…