第二章 变量和基本类型(续2) 引用 & typedef

来源:互联网 发布:linux c 字符串拷贝 编辑:程序博客网 时间:2024/06/03 15:58

2.5. 引用

引用就是对象的另一个名字。在实际程序中,引用主要用作函数的形式参数。

引用是一种复合类型,通过在变量名前添加“&”符号来定义。复合类型是指用其他类型定义的类型。在引用的情况下,每一种引用类型都“关联到”某一其他类型。不能定义引用类型的引用,但可以定义任何其他类型的引用。

引用必须用与该引用同类型的对象初始化:

      int ival = 1024;      int &refVal = ival; // ok: refVal refers to ival      int &refVal2;       // error: a reference must be initialized      int &refVal3 = 10;  // error: initializer must be an object

引用是别名

因为引用只是它绑定的对象的另一名字,作用在引用上的所有操作事实上都是作用在该引用绑定的对象上:

      refVal += 2;

refVal 指向的对象 ival 加 2。类似地,

      int ii = refVal;

把和 ival 相关联的值赋给 ii

《注解》:

当引用初始化后,只要该引用存在,它就保持绑定到初始化时指向的对象。不可能将引用绑定到另一个对象。

要理解的重要概念是引用只是对象的另一名字。事实上,我们可以通过ival 的原名访问ival,也可以通过它的别名refVal 访问。赋值只是另外一种操作,因此我们编写

      refVal = 5;

的效果是把 ival 的值修改为5。这一规则的结果是必须在定义引用时进行初始化。

初始化是指明引用指向哪个对象的唯一方法。

定义多个引用

可以在一个类型定义行中定义多个引用。必须在每个引用标识符前添加“&”符号:

      int i = 1024, i2 = 2048;      int &r = i, r2 = i2;      // r is a reference, r2 is an int      int i3 = 1024, &ri = i3;  // defines one object, and one reference      int &r3 = i3, &r4 = i2;   // defines two references

const 引用
const 引用是指向const 对象的引用:

 const int ival = 1024;      const int &refVal = ival;      // ok: both reference and object are const      int &ref2 = ival;              // error: non const reference to a const object

可以读取但不能修改 refVal ,因此,任何对 refVal 的赋值都是不合法的。这个限制有其意义:不能直接对ival 赋值,因此不能通过使用refVal 来修改ival

同理,用 ival 初始化 ref2 也是不合法的:ref2 是普通的const 引用,因此可以用来修改 ref2 指向的对象的值。通过 ref2ival 赋值会导致修改const 对象的值。为阻止这样的修改,需要规定将普通的引用绑定到const 对象是不合法的。


术语:const 引用是指向 const 的引用

C++ 程序员常常随意地使用术语 const 引用。严格来说,“const 引用”的意思是“指向const 对象的引用”。类似地,程序员使用术语“非const 引用”表示指向非const 类型的引用。这种用法非常普遍,我们在本书中也遵循这种用法。

const 引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量:

      int i = 42;      //  legal for const references only      const int &r = 42;      const int &r2 = r + i;

同样的初始化对于非 const 引用却是不合法的,而且会导致编译时错误。其原因非常微妙,值得解释一下。

观察将引用绑定到不同的类型时所发生的事情,最容易理解上述行为。假如我们编写

      double dval = 3.14;      const int &ri = dval;

编译器会把这些代码转换成如以下形式的编码:

      int temp = dval;          // create temporary int from the double      const int &ri = temp;   // bind ri to that temporary

如果 ri 不是 const,那么可以给ri 赋一新值。这样做不会修改dval,而是修改了temp。期望对 ri 的赋值会修改dval 的程序员会发现 dval 并没有被修改。仅允许const 引用绑定到需要临时使用的值完全避免了这个问题,因为const 引用是只读的。

《注解》:非const 引用只能绑定到与该引用同类型的对象。const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

2.6. typedef 名字

typedef 可以用来定义类型的同义词:

     typedef double wages;       //  wages is a synonym for double     typedef int exam_score;     //  exam_score is a synonym for int     typedef wages salary;       //  indirect synonym for double

typedef 名字可以用作类型说明符:

     wages hourly, weekly;     // double hourly, weekly;     exam_score test_result;   // int test_result;

typedef 定义以关键字typedef 开始,后面是数据类型和标识符。标识符或类型名并没有引入新的类型,而只是现有数据类型的同义词。typedef 名字可出现在程序中类型名可出现的任何位置。

typedef 通常被用于以下三种目的:

  • 为了隐藏特定类型的实现,强调使用类型的目的。

  • 简化复杂的类型定义,使其更易理解。

  • 允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。


2.7. 枚举

我们经常需要为某些属性定义一组可选择的值。例如,文件打开的状态可能会有三种:输入、输出和追加。记录这些状态值的一种方法是使每种状态都与一个唯一的常数值相关联。我们可能会这样编写代码:
const int input = 0;     const int output = 1;     const int append = 2;

虽然这种方法也能奏效,但是它有个明显的缺点:没有指出这些值是相关联的。枚举提供了一种替代的方法,不但定义了整数常量集,而且还把它们聚集成组。

定义和初始化枚举

枚举的定义包括关键字 enum,其后是一个可选的枚举类型名,和一个用花括号括起来、用逗号分开的枚举成员列表。

     // input is 0, output is 1, and append is 2     enum open_modes {input, output, append};

默认地,第一个枚举成员赋值为 0,后面的每个枚举成员赋的值比前面的大 1。

枚举成员是常量

可以为一个或多个枚举成员提供初始值,用来初始化枚举成员的值必须是一个常量表达式

常量表达式是编译器在编译时就能够计算出结果的整型表达式。整型字面值常量是常量表达式,正如一个通过常量表达式自我初始化的const 对象也是常量表达式一样。


枚举成员值可以是不唯一的。

     // point2d is 2, point2w is 3, point3d is 3, point3w is 4     enum Points { point2d = 2, point2w,                   point3d = 3, point3w };

本例中,枚举成员 point2d 显式初始化为 2。下一个枚举成员 point2w 默认初始化,即它的值比前一枚举成员的值大1。因此point2w 初始化为3。枚举成员 point3d 显式初始化为 3。一样,point3w 默认初始化,结果为4

不能改变枚举成员的值。枚举成员本身就是一个常量表达式,所以也可用于需要常量表达式的任何地方。

每个 enum 都定义一种唯一的类型

每个 enum 都定义了一种新的类型。和其他类型一样,可以定义和初始化 Points 类型的对象,也可以以不同的方式使用这些对象。枚举类型的对象的初始化或赋值,只能通过其枚举成员或同一枚举类型的其他对象来进行:

     Points pt3d = point3d; //  ok: point3d is a Points enumerator     Points pt2w = 3;       //  error: pt2w initialized with int     pt2w = polygon;        //  error: polygon is not a Points enumerator     pt2w = pt3d;           //  ok: both are objects of Points enum type

注意把 3 赋给 Points 对象是非法的,即使 3 与一个 Points 枚举成员相关联。





原创粉丝点击