C++变量和基本类型

复合类型

引用

引用(reference)为对象起了另外一个名字。

1
2
3
int ival = 1024;
int &refVal = ival; // refVal指向ival
int &refVal2; // 报错:引用必须被初始化

定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。无法令引用重新绑定到另外一个对象,因此引用必须初始化。
引用即别名 引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。
定义了一个引用之后,对其进行的所有操作都是在与之绑定的对象上进行的:

1
refVal = 2; // 把2赋值给ival

指针

指针与引用类似,也实现了对其它对象的间接访问。不同于引用的是:

  • 指针本身是一个对象,允许对其赋值和拷贝,生命周期内它可以指向几个不同的对象。
  • 指针无需在定义时赋初值。

获取对象的地址
指针存放某个对象的地址,获取该地址需要取地址符 &

1
2
int ival = 42;
int *p = &ival; // p存放变量ival的地址,或者说p是指向变量ival的指针

利用指针访问对象
如果指针指向了一个对象,则允许使用解引用符 *来访问该对象。

1
cout << *p; // 由符号*得到指针p所指的对象,输出42

空指针
空指针不指向任何对象。C++11初始化空指针的方法:

1
int *p = nullptr;

const限定符

关键字const定义常量,const对象一旦创建后其值就不能再改变了,所以const对象必须初始化。

1
const int bufSize = 512;

const的引用

可以把引用绑定到const对象上,我们称之为对常量的引用,对常量的引用不能被用作修改它所绑定的对象。

1
2
const int ci = 1024;
const int &r1 = ci; // 引用及其对应的对象都是常量

指针和const

指向常量的指针(pointer to const)不能用于改变其所指对象的值,要想存放常量对象的地址,只能使用指向常量的指针。

1
2
const double pi = 3.14;
const double *cptr = &pi; // cptr可以指向一个双精度常量

指针是对象而引用不是,允许把指针本身定为常量。常量指针(const pointer)必须初始化,*放在const关键字之前用以说明指针是一个常量,即不变的是指针本身的值而非指向的那个值。

1
2
int errNumb = 0;
int *const curErr = &errNumb; // curErr将一直指向errNumb

顶层const

用名词顶层const表示指针本身是个常量,而用名词底层const表示指针所指的对象是一个常量。

1
2
3
4
5
int i = 0;
int *const p1 = &i; // 不能改变p1的值,顶层const
const int ci = 42; // 不能改变ci的值,顶层const
const int *p2 = &ci; // 可以改变p2的值,底层const
const int &r = ci; // 用于声明引用的const都是底层const

处理类型

类型别名

类型别名(type alias)是一个名字,它是某种类型的同义词。有两种方法定义类型别名:

  • 传统方法是用关键字typedef
    1
    2
    3
    4
    5
    typedef double wages; // wages是double的同义词
    typedef wages base, *p; // base是double的同义词,p是double*的同义词

    typedef unsigned long (* _prepare_kernel_cred)(unsigned long cred);
    _prepare_kernel_cred prepare_kernel_cred;

以上两句就相当于:unsigned long (*prepare_kernel_cred)(unsigned long cred);
定义了一个函数指针prepare_kernel_cred,函数参数为(unsigned long cred),返回值为unsigned long。
建立一个类型别名的方法很简单,在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头。

  • 新标准使用别名声明(alias declaration)
    1
    using SI = Sales_item; // SI是Sales_item的同义词

这种方法用关键字using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名。

auto类型说明符

编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候就清楚地知道表达式的类型。然而有时做不到这样,因此,C++11新标准引入了auto类型说明符,它能让编译器替我们去分析表达式所属的类型,让编译器通过初始值来推算变量的类型。auto定义的变量必须有初始值。

1
2
3
auto item = val1 + val2; // item初始化为val1和val2相加的结果
auto i = 0, *p = &i; // 正确:i是整数、p是整形指针
auto sz = 0, pi = 3.14; // 错误:sz和pi的类型不一致

decltype类型指示符

有时希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。C++11新标准引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值:

1
2
3
4
5
decltype(f()) sum = x; // sum的类型就是函数f的返回类型
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x的类型是const int
decltype(cj) y = x; // y的类型是const int &, y绑定到变量x
decltype(cj) z; // 错误:z是一个引用,必须初始化