每一位 C++ 程序员都有自己的一套编程风格。这就引来了各种问题:哪儿应该 插入空白符号、怎么摆放分隔符(大括号、小括号)…等等。我们尽量保持全书风格一致, 当然有时候我们也对特殊问题作出让步。例如在教本(初阶)部份我们鼓励以空白符号和较具体的命名方式提高程序可读性,而在高阶主题中,较紧凑的风格可能更加适宜。
我们有一个他人不太常用的习惯,用以声明类型(types)、参数(parameters)和变量(variables), 希望你能多加注意。下面数种方式无疑都是合理的:
void foo (const int &x); void foo (const int& x); void foo (int const &x); void foo (int const& x);
尽管较为罕见,我们还是决定在表达「固定不变的整数」(constant integer)时使用 int const而不写成 const int。这么做有两个原因,第一,这很容易显现出「什么是不能变动的(what isconstant)」。不能变动的量总是 const 饰词之前的那个东西。尽管以下两式等价:
const int N = 100; //一般人可能的写法
int const N = 100; //本书习惯写法
但对以下述句来说就不存在所谓的等价形式了:
int* const bookmark; // 指针 bookmark 不能变动,但指针所指内容(int)可以变动
如果你把 const 饰词放在运算符 * 之前,那就改变了原意。本例之中不能变动的是指针本身,不是指针所指的内容。
第二个原因和语法替换原则(syntactical substitution principle)有关,那是处理 template 程序代码时常会遭遇的问题。考虑下面两个类型定义:
typedef char* CHARS; typedef CHARS const CPTR; // 一个用以「指向 chars」的 const 指针,如果我们做文字上的替换,把 CHARS 替换为其代表物,上述第二个声明的原意就得以保留: typedef char* const CPTR; // 一个用以「指向 chars」的 const 指针。然而如果我们把 const 写在被修饰物之前,上述规则便不适用。考虑上述声明的另一种变化: typedef char* CHARS; typedef const CHARS CPTR; // 一个用以「指向 chars」的 const 指针,现在,对 CHARS 进行文字替换,会导出不同的含义: typedef const char* CPTR; // 一个用以「指向 const chars」的指针
面对volatile饰词,也有同样考虑。关于空白符号,我们决定把他放在"&"符号和参数名称中间:
void foo (int const& x);
这样可以更加突出参数的类型和名称。无可否认,以下声明方式可能较易引起疑惑:
char *a, b;
根据从 C 语言继承下来的规则,a 是个指针而b 是个一般的 char。为了避免这种混淆,我们可以一次声明一个变量,不要集中于同一行声明语句。
本书并不是一本讨论C++标准库的书,但我们确实在一些例子中用到了标准库。一般 来说,我们使用C++特有的 头文件(例如<iostream> 而非<stdio.h>) 。惟一的例外是<stddef.h>,我们使用它而不使用<cstddef>,以避免类型 size_t 和 ptrdiff_t 被冠以 std::前缀词。这样做更具可移植性,而且 std::size_t 并不比 size_t 多出什么好处。
#include<cstdio> #include<iostream> using namespace std; int main() { const int N=100; int const N=100; //二者等价 int mark=0; //1 int* ref_mark=&mark; int* const book1=ref_mark;//指针book1是个常量,并没有说明这个指针指向的int值是个常量 const int* book2=ref_mark;//指针book2是个指针类型的常量 cout<<"N1:"<<N1<<endl; cout<<"N2:"<<N2<<endl; *book1=10; cout<<*book1<<endl; *book2=20; /* |error: assignment of read-only location ‘* book2’| const int *book2=ref_mark */ cout<<*book1<<endl; cout<<*book2<<endl; //2 typedef char* CHARS; typedef CHARS const CPTR; //替换后 typedef char * const CPTR; //仍然是指向char类型的常量指针 typedef const CHARS CPTR; //替换后 typedef const char * CPTR; //是指向char类型的指针 }