第二章-变量和基本类型2

来源:互联网 发布:微信公众号做淘宝客 编辑:程序博客网 时间:2024/06/05 06:15

第二章-变量和基本类型2

关于C++的几篇博客,参考人民邮电出版社的《C++ Primer 中文版》一书。

在上一篇博客《第二章-变量和基本类型》中,我们介绍了C++的内置类型和变量的基本概念,这篇博客则着重介绍几种比较特殊的变量类型,包括const变量、枚举变量enum、类型定义typedef、引用、类类型class。其中,可以这样理解,const、enum、typedef(另外还包括extern)它们都是放在变量类型关键字前面的限定符,对当前基本变量(或用户自定义变量)加上某种限制或者赋予某种含义。下面我们来一一介绍。

一、const

1、定义:之所以需要有这样一种变量存在,是因为:如果我们在程序中需要反复使用一个不变的常量,那么我们不如定义一个变量,并赋值给它一个常量,这样程序每次调用该变量名就可以了;接下来,如果程序很复杂,变量名很多很复杂,我们有可能会意料之外地不小心修改了这个变量,这又会是不安全的。所以我们需要这样一个变量,它不需要改变,且不能被改变,这就是const限定符的作用。

2、属性:

(1)const 把相应类型的对象转变为一个常量,常量不能被修改,所以const变量也不可以被修改,否则会出编译错误。

(2)因为const常量在定义后就不能够修改,所以定义时必须初始化。

(3)const 对象默认为文件的局部变量。举以下三个例子说明:

例1:

假设我们有

// file1.cpp

int counter;

我们想在file2.cpp中对counter进行操作,正确的做法是:

// file2.cpp

extern int counter;

counter++;


例2:

// file1.cpp

const int counter;

// file2.cpp

extern const int counter;

这种做法就是错误的。因为const 对象默认是局部于文件创建的,不能被其他文件读取,即便是加上外部声明extern。那么,正确的做法应该是:


例3:

// file1.cpp

extern const int counter;

// file2.cpp

extern const int counter;

counter++;


综上,也就是说,文件中的一般全局变量默认是可以被其他文件使用的,而const全局变量则默认是独立于文件、局部于文件创建的,不可以被其他文件使用,除非在定义时就加上extern关键字,将其定义为extern const的全局变量。

我们可以这样形象化地理解这个问题,假想作用域、可见范围等的概念是一层一层向外扩展的。不加const限定符定义的变量,它本身就是一个在当前工程下的各个文件中均可见的变量,那么在其他文件中使用它时,只需要在使用前用extern声明一下即可。然而,加了const限定符的变量,其可见范围只在当前定义它的文件下,需要加个extern才能将可见范围扩展到整个工程的所有文件下,然后就跟不加const限定符一个效果了。

也就是在这个问题中,我们可以形象地认为加extern关键字的作用,就是将可见范围向外扩展一层。


综上所述,非const变量默认为extern,而const变量则是独立于、局部于文件创建的。要使const变量能够在其他文件中访问,必须显示地指定它为extern。


二、enum

我们首先通过一个例子来了解一下enum枚举存在的意义。

例如,文件打开的状态可能有三种:输入、输出和追加。记录这些状态值的一种方法是每种状态都关联一个唯一的常数值。我们或许可以这样定义三种状态:

const int input = 0;

const int output = 1;

const int apped = 2;

虽然这种方法是有效的,但是明显的缺点是:我们看不出这三个常量之间是相关联的。枚举,就解决了这个问题,不但定义了整数常量集,而且还把它们聚集成组。如下:

enum fileState { input, output, append };     // 默认input =0,output =1,append =2。注意 fileState 是枚举类型名,而不是定义


枚举变量的属性:

(1)枚举成员是一个常量表达式,所以不能修改。

(2)举例说明几点规则:

enum fileState { input, output, append };

fileState file1_state = input;     // 合法

fileState file2_state = 2;           // 不合法,尽管2对应一个成员值

file1_state = file2_state;          // 合法

int i = 1;                                     

file1_state = i;                           // 不合法,必须得是相同的枚举类型才可以这样赋值

三、typedef:给数据类型起新名字

typedef可以用来定义类型的同义词,格式如下:typedef      数据类型(旧名称)      标识符(新名称)

标识符(新名称)并没有引入新的类型,只是现有数据类型(旧名称)的同义词,可出现在该数据类型可出现的任何位置。

四、引用:给变量起新名字

1、定义:类型可以起新名字,变量也可以起新名字。这就是引用的作用,相当于给变量起了个新名字。

2、属性:

(1)初始化是指明引用指向哪个对象的唯一方法,因此定义引用时必须进行初始化。

(2)有很多规则,与其用拗口的语言描述做归纳总结,不如举例说明问题。尽量包含所有可能的情况吧,可以感受一下。

例1(非const引用,引用const对象不合法;反过来是合法的):

const int val=1024;

const int &ref1 = val;     // 正确!

int &ref2 = val;                // 错误!


例2(关于引用常量,只能用const引用才合法):

const int &ref1 = 1024;    // 正确!

int &ref1 = 1024;               // 错误!


例3(关于引用右值,只能用const引用才合法):

int ival = 1024;

const int &ref1 = 42;                    // 正确!

const int &ref2 = ival + ref1;       // 正确!

int &ref3 = ival + ref1;                 //  错误!(因为这样就失去了为另外一个变量起新名字的意义,不存在另外一个变量了)


综上,非const引用只能绑定到与该引用“同类型“的“对象“,不可引用常量或右值。

然而,const引用可以绑定到“常量“、“右值”或“不同但相关“的类型的“对象“。

以上,引号“ ”是为了突出强调!


五、class

类,定义了该类型的对象包含的数据和该类型的对象可以执行的操作。标注库类型string、ostream和istream都是定义成类的。

设计类的定义时,思路是这样的:该类的对象需要执行哪些操作,这些操作又需要哪些数据。前者或许可以通过定义成员函数来实现,后者就是类的成员变量了。

1、数据成员的初始化:

类的数据成员的初始化并不是在定义类或者定义数据成员时实现的,而是通过一个叫作构造函数的东西。

这个构造函数可以在类的定义中进行显示的定义,如果不显示定义,也会由隐式的默认构造函数对成员变量进行初始化。

2、访问标号:public、private

类的成员函数可以使用类的任何成员,而不管其访问级别。

public成员可以被程序的任何部分访问。一般把操作都放在public里,这样方便定义该类的程序调用这些操作。

private成员只能被类的组成部分的代码访问,而不能被类外部的程序访问。

3、class与struct的区别

用class和struct关键字定义类的唯一差别就在于默认的访问级别:默认情况下,struct的成员是public,而class的成员是private。

0 0
原创粉丝点击