引用(C++ 推荐 使用引用技术,因为语法方便。引用的本质是指针常量,但是所有的指针操作编译器都帮我们做了)
引用的基本使用
作用:给变量起别名(两个变量除了名字外是完全相同的)
语法:数据类型 &别名 = 原名;
?
#include?<iostream>
#include?<string>
using?namespace?std;
int?main()
{
????????int?a = 10; // 原名
????????int?&b = a; // 引用(起别名)
????????cout <<?"a = :"?<<?a <<?endl;
????????cout <<?"b = :"?<<?b <<?endl;
????????b = 1001; // 修改别名的内容
????????cout <<?"a = :"?<<?a <<?endl;
????????cout <<?"b = :"?<<?b <<?endl;
????????system("pause");
????????return?0;
}
运行结果:
?
引用的注意事项
1、引用必须初始化
解释:int &b; // 这就是错误的,因为没有经过初始化
2、引用在初始化后,不可以改变(只可以当一个变量的别名,不可以再改成其他变量的别名)
int &b = a;
int &b = c; // 错误,因为b已经是a的别名了,不可以被改成其他变量的别名
引用做函数参数
作用:函数传参时,可以利用引用的技术让形参修饰实参(与形参是指针的作用相同)
优点:可以不使用指针来修改实参
#include <iostream>
#include <string>
using namespace std;
// 1、值传递
void SWAP01(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
// 2、地址传递
void SWAP02(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// 3、引用传递(作用和2、地址传递作用相同)
void SWAP03(int &a, int &b) // 引用传递时,传进来的就是实参a和b“本身”(别名),而不是a、b的副本
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
SWAP01(a, b); // 1、值传递(形参不修饰实参)
cout << "SWAP01 a = :" << a << endl;
cout << "SWAP01 b = :" << b << endl;
SWAP02(&a, &b); // 2、地址传递(形参会修饰实参)
cout << "SWAP02 a = :" << a << endl;
cout << "SWAP02 b = :" << b << endl;
SWAP03(a, b); // 3、引用传递(形参会修饰实参,作用和2、地址传递一样)
cout << "SWAP03 a = :" << a << endl;
cout << "SWAP03 b = :" << b << endl;
system("pause");
return 0;
}
运行结果:
引用做函数的返回值
作用:引用可以作为函数的返回值存在
【注意】不要返回局部变量的引用(同“不要返回局部变量的地址”类似)
??????????????函数调用还可以作为左值
#include?<iostream>
#include?<string>
using?namespace?std;
// 引用做函数的返回值
// 1、不要返回局部变量的引用
int& test01() // 引用的方式作为函数的返回
{
????????int?a = 10; //存放在栈区(函数执行完a就被释放)
????????return?a; // 返回局部变量(由于返回值类型为引用,所以这是在返回局部变量a的引用,也就是返回局部变量a的别名)
????????// 注意这种操作是非法的,因为它返回的是局部变量a的引用(别名),也就是说它返回的其实就是a本身(而不是a的值)
}
// 2、函数的调用可以作为左值
int& test02()
{
????????static?int?a = 10; // 存放在全局区,在全部的程序结束后由系统释放
????????return?a; //这种情况就没有问题,因为执行完test02()后,a不会被释放
}
int?main()
{
????????int?&ref = test01(); // 由于返回值类型为引用,所以将引用ref来作为局部变量a的别名
// 等效为 int &ref = a;?但a所在的地址空间已经被释放了,里面的值已经不是10了
// 所以这一步可以看出,int &ref = a;其实是让 ref 与 a 指向同一个地址
????????cout <<?"ref = "?<<?ref <<?endl;
????????int?&ref2 = test02(); // ref2和静态局部变量a指向同一个地址,执行完test02()后a并没有被释放,因此下面的输出是正确的
????????cout <<?"ref2 = "?<<?ref2 <<?endl;
????????cout <<?"ref2 = "?<<?ref2 <<?endl;
????????test02() = 1000; // 返回值为引用类型时,函数调用可以作为左值
// 这句等效为a = 1000;因为test02()返回的就是a,注意不是a的值
????????cout <<?"ref2 = "?<<?ref2 <<?endl;
????????cout <<?"ref2 = "?<<?ref2 <<?endl;
????????system("pause");
????????return?0;
}
运行结果:?
?
引用的本质
本质:引用的本质在C++内部实现是一个指针常量(即常量类型的指针,也即该指针本身就是一个常量)
int &ref = a; // 会自动转换为?int * const ref = &a;?所以ref不能是其他变量的别名(引用一旦初始化后,就不可以发生改变)
#include?<iostream>
#include?<string>
using?namespace?std;
void?func(int?&ref)
{
????????ref?= 100; // 发现ref是引用,自动转成 *ref = 100;
}
int?main()
{
????????int?a = 10;
????????int?&ref = a; // 发现是引用,转换为int * const ref = &a
????????ref = 20; // 发现ref是引用,自动转成 *ref = 20;
????????cout <<?"a = "?<<?a <<?endl;
????????cout <<?"ref = "?<<?ref <<?endl;
????????system("pause");
????????return?0;
}
运行结果:
?
结论:C++ 推荐 使用引用技术,因为语法方便。引用的本质是指针常量,但是所有的指针操作编译器都帮我们做了。
常量引用
作用:常量引用主要用来修饰形参,防止误操作
在函数形参列表中,可以加const修饰形参,防止形参改变实参。
#include?<iostream>
#include?<string>
using?namespace?std;
void?showValue(int?&a) // 引用的方式进行接收,即传入的是实参本身
{
????????a?= 1000; // 实参会被修改
????????cout <<?"showValue val = "?<<?a?<<?endl;
}
void?showValue_2(const?int?&a) // 引用的方式进行接收,即传入的是实参本身。但由于加了const修饰,就把引用变成了一个常量。
{ // 因此形参引用的方式加const是为了防止误操作(常见的应用场景)
//a = 1000; // 此操作非法,实参不会被修改
????????cout <<?"showValue val = "?<<?a?<<?endl;
}
int?main()
{
// 常量引用
// 使用场景:用来修饰形参,防止误操作
????????int?a = 10;
// int &ref = 10;// 此操作是非法的,因为右边是常量。被引用的对象必须是在栈区或堆区的数据,而常量位于常量区,即全局区。
????????const?int?&ref = 10; // 此操作是合法的。加上const后,编译器将代码修改为 int temp = 10; const int &ref = temp;
// 也就是说现在的引用是引用一块临时的空间比如temp,但其实我们找不到它的原名(编译器起好了),我们只能通过别名ref去操控它
????????// int &ref是一个指针常量,再加一个const,就既是指针常量,又是常量指针
????????//?ref = 20; // 此操作非法,因为被ref指向的对象已经是一个常量了
????????int?val = 100;
????????showValue(val); // 由于showValue()函数是以引用的方式传递参数的,因此传入的就是实参val本身
????????cout <<?"main() val = "?<<?val <<?endl; // 验证实参是否被修改
????????system("pause");
????????return?0;
}
运行结果:
?
?
|