目录
1 复合类型
C++中最常用的两种复合类型分别是指针和引用。指针是C++继承自C的特性,引用是C++新发展的特性。它们的特点是都可以借此间接访问对象,规避拷贝行为,以此来节省空间,两者的根本区别之一在于指针是对象(内存中的具体值)而引用不是(只是对象的别名)。
1.1 引用
基本定义:
引用是对已经存在的对象所起的另一个名字,引用不是对象。
性质:
- 引用必须初始化。定义引用时,是把引用和其初始值对象绑定在一起,不是将初始值拷贝给引用。
- 一旦初始化完成,引用将始终与其初始值对象绑定在一起,无法令引用重新绑定到另一个对象。
- 引用本身不是对象,所以不能定义引用的引用。
- 除了两种特殊情况,其他所有引用的类型都要和其绑定的对象类型严格匹配。
- 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定。
- 引用被定义后,对引用的操作本质上都是在操作与之绑定的对象。
范例:
//例1
int ival = 1024;
int &refVal = ival; //定义一个int类型的引用,名字为refVal,通过将其绑定在ival这个对象上完成其初始化,绑定完成后,refVal代表ival的另一个名字
int &refVal2; //❌,引用必须被初始化
refVal = 2; //把2赋给refVal绑定的对象,即赋给ival
int i1 = refVal; //把refVal绑定的对象赋给i1,等价于i1 = ival
int &refVal3 = refVal; //将refVal3绑定到refVal指代的那个对象(即ival)上
int i = refVal; //利用refVal指代的对象(iVal)的值(1024)初始化int类型变量i
//例2
int i = 1024, i2 = 2048;
int &r = i; r2 = i2; //r是int类型的引用,绑定i;r2是int变量,由i2的值拷贝初始化
int i3 = 1024, &r3 = i3; //i3是int变量,r3是int类型的引用,绑定i3
int &r3 = i3, &r4 = i2; //i3和i4都是int类型的引用,分别绑定i3和i2
//例3
int &refVal4 = 10; //❌,不能用字面值来初始化引用
double dval - 3.14;
int &refVal5 = dval; //❌,引用的类型要与其绑定的对象类型严格匹配,不能将int类型的引用绑定在double类型的对象上
1.2 指针
基本定义:
指针是一个对象,也就是说,指针是一个实际的内存空间,其中存放的值是所指向对象的地址
性质:
- 指针可以只声明而不初始化,但建议初始化所有指针,最好在定义了对象之后再定义指向它的指针,这样就可以解决初始化的问题。如果实在不清楚指向何处,请将指针的值初始化为0或nullptr。否则仅有声明的指针是不会进行默认初始化的,其值为一个不确定的值,对这种无效指针的操作会引发未定义的后果,非常危险。
- 指针本身就是一个对象,因此允许对指针本身进行赋值和拷贝,这意味着指针在其生命周期内可以指向几个不同的对象。
- 类似引用,除了两种例外情况,其他所有指针的类型都要和他所指向的对象类型严格匹配。
- 如果指针指向了一个对象,则可通过解引用操作符(*)访问该对象。对指针解引用会得到指针所指的对象本身,如果给解引用的结果赋值,实际就是给指针所指的对象赋值。
范例:
//例1
int *ip1, *ip2; //声明ip1和ip2都是指向int类型对象的指针,此时它们还未被初始化,拥有未确定的值
double *dp2, dp; //声明dp2是指向double类型对象的指针,有用未确定的初值,声明dp是double类型的变量,被默认初始化为0.0
int ival = 42;
int *p = &ival; //通过ival的地址来初始化int类型的指针p,此时可以说p指向ival
double dval;
double *pd = &dval