变量名,本身是一段内存的引用,即别名(alias)。引用可以看作一个已定义变量的别名。
引用的语法:Type &name = var;
用法如下:
int a = 10; // 编译器分配4个字节的内存空间,a为此内存空间的别名,可以通过a来修改内存空间的值
int &b = a; // b为a的引用,即b为a的别名,同样可以通过b来修改内存空间的值
int a, b;
int &r = a; // 正确,变量与引⽤用具有相通的地址
int &r = b; // 错误,不可以修改原有的引用关系
float &rr = b; // 错误,引用类型不匹配
int &ra = r; // 正确,可以对引用再次引用,此时a有两个别名r和ra
普通引用在声明时必须用其它的变量进行初始化,引用作为函数参数声明时不进行初始化。
void test01(int &i) // 形参为引用,相当于对传入形参起别名
{
r = 100; // 相当于修改了主函数中a为100
return;
}
void test02(int j)
{
j = 1000;
}
int main()
{
int a = 10;
cout << a << endl; // a = 10
test01(a); // 当传a进去时,i为a的别名,i与a为相同的内存地址
cout << a << endl; // a = 100;
test02(a);
cout << a << endl; // a = 100;
}
Type& name <===> Type const name*
间接赋值的3各必要条件
- 定义两个变量 (一个实参一个形参)
- 建立关联 实参取地址传给形参
- *p形参去间接的修改实参的值
引用在实现上,只不过是把:间接赋值成立的三个条件的后两步和二为一.
当实参传给形参引用的时候,只不过是c++编译器帮我们程序员手工取了
一个实参地址,传给了形参引用(常量指针) 。
不能成为其它引用的初始值(不能作为左值使用)
尽量不要返回栈变量作引用
#include
using namespace std;
int getA1()
{
int a;
a = 10;
return a;
}
int& getA2()
{
int a;
a = 10;
return a;
}
int main()
{
int a1 = 0;
int a2 = 0;
// 值拷贝
a1 = getA1();
// 将一个引用赋给一个变量,会有拷贝动作
// 理解:编译器类似做了如下隐藏操作,a2 = *(getA2());
a2 = getA2();
// 将一个引用赋给另一个引用作为初始值,由于是栈内存的引用(函数getA2中变量a为栈内存,出了作用域就栈内存就释放了),内存非法
//int &a3 = getA2();
cout << "a1 = " << a1 << endl;
cout << "a2 = " << a2 << endl;
// cout << "a3 = " << a3 << endl;
return 0;
}
可以成为其他引用的初始值(可作为右值使用,也可作为左值使用)
#include
using namespace std;
int getA1()
{
int a;
static a = 10;
return a;
}
int& getA2()
{
int a;
static a = 10;
return a;
}
int main()
{
int a1 = 0;
int a2 = 0;
// 值拷贝
a1 = getA1();
// 将一个引用赋给一个变量,会有拷贝动作
// 理解:编译器类似做了如下隐藏操作,a2 = *(getA2());
a2 = getA2();
// 将一个引用赋给另一个引用作为初始值,由于是静态区域,内存合法
int &a3 = getA2();
cout << "a1 = " << a1 << endl;
cout << "a2 = " << a2 << endl;
cout << "a3 = " << a3 << endl;
return 0;
}
- 如果返回值为引用可以当左值。(返回变量本身)(全局/静态变量)
- 如果返回值为普通变量不可以当左值。(返回变量的值)
#include
using namespace std;
// 函数当左值
// 返回变量的值
int func1()
{
int a;
static a = 10;
return a;
}
// 返回变量本身
int& func2()
{
int a;
static a = 10;
return a;
}
int main()
{
int a1 = 0;
int a2 = 0;
// 函数当右值
a1 = func1();
cout << "a1 = " << a1 << endl; // a1 = 10
// 函数返回值是一个引用,并且当右值
a2 = func2();
cout << "a2 = " << a2 << endl; // a2 = 10
// 函数当左值
//func1 = 100; // 错误
func2 = 100; // 函数返回值是⼀一个引⽤用,并且当左值
int a3 = func2();
cout << "a3 = " << a3 << endl; // a3 = 100
return 0;
}
//1.直接建立引用
int arr[10];
int(&pArr)[10] = arr;
// 使用
pArr[0] = 1; // 相当于arr[0] = 1;
----------------------------------------------------------------
//2.先定义出数组类型,再通过类型 定义引用
int arr[10];
typedef int(ARRAY_TYPE)[10]; // 创建出10个int类型的数组,叫ARRAY_TYPE,即ARRAY_TYPE为10个int类型的数组
ARRAY_TYPE & pArr2 = arr;
// 使用
pArr2[0] = 1; // 相当于arr[0] = 1;
#include
using namespace std;
struct Person
{
string name;
int age;
};
void getPerson01(Person **p)
{
(*p)->name = "张三";
(*p)->age = 18;
return;
}
void getPerson02(Person *&p)
{
p->name = "李四";
p->age = 20;
return;
}
int main()
{
Person *pP = new Person;
//1 c语⾔言中的⼆二级指针
getPerson01(&pP);
cout << "姓名:" << pP->name << " 年龄:" << pP->age << endl;
//2 c++中的引⽤用 (指针的引⽤用)
//引⽤用的本质 间接赋值后2个条件 让c++编译器帮我们程序员做了
getPerson02(pP);
cout << "姓名:" << pP->name << " 年龄:" << pP->age << endl;
delete pP;
return 0;
}
利用引用可以简化指针
可以直接用同级指针的引用,给同级指针分配空间
const 引用有较多使用。它可以防止对象的值被随意修改。因而具有一些特性。
1.const 对象的引用必须是const的,将普通引用绑定到const对象是不合法的。
const int a =1; // const变量
int &b = a; // 普通引用b绑定到const对象不合法
------------------------------------------------------------
int x = 1;
const int &y = a; // 合法,常引⽤用是限制变量为只读 不能通过y去修改x了
// y = 2; // 错误
const int a =1; // const变量
const int &b = a; // 合法
------------------------------------------------------------
double x = 3.14;
const int &y = x; // 合法 y = 3;
const int &ref = 10;
// 加了const之后,相当于写成 int temp = 10; const int &ref = temp;
//常量引用的使用场景:修饰函数中的形参,防止误操作
void test(const int &a)
{
a = 10; // 错误
}
const 引用的目的是,禁止通过修改引用值来改变被引用的对象。
const 引用的初始化特性较为微妙,可通过如下代码说明:
double val = 3.14;
const int &ref = val; // 使用相关类型的对象初始 相当于 int temp = val; const int &ref = temp;
double &ref2 = val;
cout << ref << " " << ref2 << endl;
val = 4.14;
cout << ref << " " << ref2 << endl;
上述输出结果为3 3.14和3 4.14。因为ref是const的,在初始化的过程中已经给定值,不允许修改.而被引用的对象是val,是非const的,所以val的修改并未影响ref的值,而ref2的值发生了相应的改变。
为什么非const的引用不能使用相关类型(常量,非同类型的变量或表达式)初始化呢???
实际上,const 引用使用相关类型对象初始化时发生了如下过程: int temp = val; const int &ref = temp;
如果 ref 不是const的,那么改变ref 值,修改的是 temp,而不是 val。期望对ref的赋值会修改val的程序员会发现val实际并未修改。
因此不允许使用相关类型初始化非const引用
// 1.⽤用变量 初始化 常引⽤用
int x1 = 30;
const int &y1 = x1; // 用x1变量初始化 常引用
// 2.用字面量初始 常量引用
const int a = 40; // c++编译器把a放在符号表中
// int &m = 41; // 错误
const int &m = 42; // c++ 会分配内存空间
// 相当于 int temp = 42; const int &m = temp;
结论:
- const int & e 相当于 const int * const e
- 普通引用 相当于 int *const e
- 当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名
- 使用字面量对const引用初始化后,将生成一个只读变量