复合类型是指其他类型定义的类型
C++有集中复合类型,引用和指针是其中两种
复合类型变量的定义要复杂很多
1 引用
C++ 11包含左值引用和右值引用,一般的引用都是指左值引用
引用为对象另外一个名字,用&d的形式来定义
int ival = 1024;
int &refVal = ival; // refVal指向ival,是ival别名
int &refVal2; // 错误,引用必须初始化
程序将引用和它的初始值绑定,而不是将初始值拷贝给引用
完成初始化,则引用与初始值对象绑定在一起
引用必须初始化
#include <iostream>
int main()
{
int i = 1;
int &a = i; // 正确,将a与i绑定在一起
int &a = 1; // 错误,引用只能与对象绑定
a = 10; // 正确,相当于同时修改了a和i的值
int &b = a; // 正确,再给a起别名b
int &b = &a;// 错误,引用本身不是对象,不能定义引用的引用
std::cout << i << std::endl;
return 0;
}
允许一条语句定义多个引用,每个引用标识符必须以&开头
引用的类要与之绑定的对象严格匹配(有特例)
引用只能绑定对象,不能与字面值或表达式计算结果绑定
2.3.1 练习
-
2.15判断定义合法性
(a)int ival = 1.01; // 合法,但会强制转换为1
(b)int &rvall = 1.01;//不合法,引用不能与字面值绑定
(c)int &rval2 = ival;// 合法引用
(d)int &rval3; // 不合法,引用必须初始化 -
2.16 考察赋值合法性
int i = 0, &r1 = i;
double d = 0, &r2 = d;
(a) r2 = 3.14159; // 合法
(b) r2 = r1; // 合法
© i = r2; // 合法
(a) r1 = d; // 合法 -
执行代码结果
#include <iostream>
int main()
{
int i, &ri = i;
i = 5;
ri = 10;
std::cout << i << " " << ri << std::endl;
return 0;
}
输出结果都是10,因为ri引用指向对象i,所以ri是i的别名,经过两次赋值,最终两个变量值都是10
2 指针
指针与引用相似,实现对象的简介访问
指针与引用不同在于,一是指针本身就是对象,允许赋值和拷贝,允许定义指向指针的指针,二是指针定义时可以不初始化
int *p1, *p2; //p1和p2都是指向int型对象的指针
double dp, *dp2;// dp2是指向double型对象的指针,dp是double型对象
指针存放某个对象的地址,要想获取该地址,需要使用取地址符&
int *p = &ival;意思是p是指向变量ival的指针,p存放变量ival的地址
因为引用不是对象,没有实际地址,所以不能定义指向引用的指针
指针类型和其所指向的对象类型必须相同(有特例)
指针的值(即地址)包含4种状态,指向一个对象、指向紧邻对象所占空间的下一位置、空控制、无效指针
int *val = 42;
double dp = &val;
指向对象的指针 dp存放变量val的地址,由解引用符*号访问dp指向对象
对指针解引用结果赋值,也是给指针所指向对象赋值
不同符号不同位置区分:
- &出现在紧随类型名,是声明,定义引用
- &出现在表达式,是取地址符
- *出现在紧随类型名,是声明,定义指针
- *出现在表达式,是解引用符
#include <iostream>
int main()
{
int i = 10;
int *p = &i;
int &r1 = *p; //正确,*p指向i,定义&r引用与对象*p(i)绑定
int &r1 = p; // 错误,定义引用要与对象绑定,p的值是地址
std::cout << r1 << std::endl;
return 0;
}
空指针不指向任何对象,定义时可以初始化为nullptr、0、NULL
C++ 11最好使用nullptr,而不使用NULL
不能把变量直接付给指针
void是特殊的指针,可以存放任意对象的地址
指针符号要与变量名紧挨在一起
**表示指向指针的指针
**表示指向指针的指针的指针
#include <iostream>
int main()
{
int i = 10;
int *p1 = &i;
int **p2 = &p1;
// i的值是字面值,&i的值是i的地址
std::cout << i << ',' << &i << std::endl;
// p1的值是i的地址(&i), &p1的值是指针p1的地址
std::cout << p1<< ',' << &p1 << std::endl;
// p2是指针p1的地址,*p2的值是i的地址,**p2是i
std::cout << p2 << ',' << *p2 << std::endl;
return 0;
}
引用并不是对象,所以不能定义指向引用的指针
指针是对象,可以定义对指针的引用
int i = 42;
int *p; // p是一个int型指针
int *&r = p; // r是一个对指针p的引用
r = &i; // r引用了一个指针,给r赋值相当于令指针p指向i
*r = 0; // 解引用r得到i,也就是p指向对象i的值进行修改
理解变量的类型,需要根据变量从紧挨变量从右往左识别