目录
一、引用变量
引用变量相当于不可变指针的语法糖,在汇编层面引用变量的变量名等同于*p,p是指向原变量的不可变指针,修改引用变量等同于修改原变量,程序依然会将引用变量当指针一样为其分配独立的内存,但是无法通过&获取分配给引用变量的内存地址;当作为参数传递到方法或者函数时,传递的是原变量的地址,其行为跟传递原变量的不可变指针一样。引用与指针的区别如下:
- 不存在空引用,引用必须连接到一块合法的内存,而允许空指针
- 引用必须在声明时初始化指向一个变量,且不能改变所指向的变量,二次赋值实际是对所指向的变量赋值而不是对引用变量本身赋值。而指针在声明时可以不初始化,可以在任何时候指向到另一个对象。
- 指针代表着地址,而引用代表着变量。sizeof 指针,是指针的大小,sizeof 变量,是变量的大小
1、引用变量声明
基本类型变量,指针,数组,结构和类变量都可以声明对应的引用变量
#include <iostream>
#include <string>
int main() {
using namespace std;
int rats = 101;
//int &表示声明一个指向int变量的引用变量,rodents可以与rats等价使用
//引用变量相当于不可变指针的语法糖,rodents等价于*pt,但是程序不会给rodents分配内存,只是语义层面rats的一个别名
int & rodents = rats;
int* const pt = &rats;
//必须在声明时初始化引用变量
// int & a;
// a=rats;
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
rodents++;
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
rats++;
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
(*pt)++;
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
int a2 = 10;
//引用变量不能二次赋值,只能在声明时赋值,二次赋值表示对所引用的变量rats赋值
rodents = a2;
cout << "rats = " << rats;
cout << ", rodents = " << rodents << endl;
//rats和rodents内存地址相同,a2同rodents不同
cout << "rats address = " << &rats;
cout << ", rodents address = " << &rodents << endl;
cout << ", a2 address = " << &a2 << endl;
//同const指针,表示不能通过引用变量a3修改被引用变量a2的值
const int & a3=a2;
//编译报错
// a3=2;
a2=10;
cout << "a2 = " << a2;
cout << ", a3 = " << a3 << endl;
//声明指针变量的引用变量
int* const &q = pt;
cout << "pt address = " << &pt;
cout << ", q address = " << &q << endl;
//声明数组变量的引用变量
int rats2[4] = { 1, 2 };
int (&rodents2)[4] = rats2;
cout << "rats2[1] address = " << &rats2[1];
cout << ", rodents2[1] address = " << &rodents2[1] << endl;
struct user {
int age;
char name[5];
};
//c++中可以省略关键字struct,相当于编译器做了typedef
user u={12,"test"};
//声明结构变量的引用变量
user & u2=u;
cout << "u.name address = " << &u.name;
cout << ", u2.name address = " << &u2.name << endl;
string s="shl";
//声明类变量的引用变量
string & s2=s;
cout << "s address = " << &s;
cout << ", s2 address = " << &s2 << endl;
return 0;
}
2、引用变量作为函数入参
引用变量作为入参时同指针作为入参一样,可以减少变量复制的性能损耗和内存占用,提高函数调用性能,但是会函数对变量的修改会作用于原来的变量,而普通的值传递时传递到函数中的是原变量的副本,函数对变量的修改不会影响原变量。另外引用变量作为入参时同指针,相比值传递,对变量类型有严格校验,如果是1,"test"这类字面常量或者a+1这类表达式作为入参时会因类型不符报错,如果要求的是int & 或者int *,但是传递的是long &或者long *,一样因类型不符报错。C++为了增加引用变量的适用性,如果函数定义中引用变量入参是const,则编译器会自动为这类类型不符的变量创建一个符合入参类型要求的临时变量,将字面常量或者表达式的值赋值给临时变量,必要时做类型转换如将long转成int,然后将临时变量的引用变量作为入参传递到函数中。
#include <iostream>
using namespace std;
void swapr(int & a, int & b); // a, b are aliases for ints
void swapp(int * p, int * q); // p, q are addresses of ints
void swapv(int a, int b); // a, b are new variables
void swapr2(const int & a);
int main() {
int wallet1 = 300;
int wallet2 = 350;
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Trying to use passing by value:\n";
//值传递,函数使用值的副本,不会对原来的变量产生影响
swapv(wallet1, wallet2);
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Using pointers to swap contents again:\n";
//指针传递,本质还是值传递,不过是指针的值
swapp(&wallet1, &wallet2);
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Using references to swap contents:\n";
//引用传递,本质是指针传递,会修改原来的变量
swapr(wallet1, wallet2);
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
//编译报错,类型不符,1是字面常量,a+1是表达式,这两个都是右值,即无法被引用的数据对象
//无法被引用可以通俗理解无法用&获取该数据对象的内存地址
// swapr(1,2);
//指针一样报错
// swapp(1,2);
int a=1,b=2;
// swapr(a+1,b+2);
// swapp(a+1,b+2);
long a2=1,b2=12;
//编译报错,类型不符,编译器不会无法将指向long的引用变量强转成指向int的引用变量
// swapr(a2,b2);
//指针传递,一样报错,不能对指针类型强制转换
// swapp(&a2,&b2);
//但是如果引用变量入参被声明成const,则编译器会创建一个临时变量并初始化为对应的值,然