C++学习笔记(十九):有关引用的总结

前言
作者简介:大家好,我是翼同学,一名大学生。
个人主页:翼同学的CSDN博客
系列专栏:C++学习笔记
备注:如果文章有误,请指正,万分感谢!让我们一起学习,一起进步。
✅最后:如果文章对您有帮助,请三连支持一下博主哦。

目录

  • 1.什么是引用
  • 2.引用的使用
    • 2.1.创建引用
    • 2.2.注意事项
  • 3.引用作为函数参数
    • 3.1.引用作为参数
    • 3.2.小结:
  • 4.用引用返回多个值
  • 5.常量引用
  • 6.引用作为函数返回值
    • 6.1.返回引用
      • 6.1.1.方式1解析
      • 6.1.2.方式2解析
      • 6.1.3.方式3解析
      • 6.1.4.方式4解析
    • 6.2.注意事项

1.什么是引用

我们使用引用来给已经存在的变量赋予别名,这样,我们就可以使用该别名来指向变量

  • 引用就是别名
  • 对引用的修改就相当于对实际目标的修改

2.引用的使用

2.1.创建引用

创建引用时,我们先写上目标的数据类型,后接&,再加上别名,最后把目标赋给引用即可

举例:

int var = 4;

int& v = var;

在这里,我们声明v是变量var的引用。

2.2.注意事项

如下:

  1. 引用的变量必须已经声明了或定义了(即在上述代码中,变量var必须已经声明了)
  2. 引用在声明是必须初始化(即int & v;是错误的,其未初始化)
  3. 引用运算符&只在声明时使用,其余情况都是指取地址运算符
  4. 一旦引用被初始化为一个对象,就不能被指向到另一个对象
  5. 实际上,引用的地址就是其引用的对象的地址(求引用本身的地址其实并无意义)
  6. 指针也是内存实体,所以指针也可以有引用,比如:int* var; int* & v = var;
  7. 不存在空引用,即int & v = NULL;这条语句毫无意义

3.引用作为函数参数

3.1.引用作为参数

传递引用给函数和传递指针给函数,效果都一样。即传递的是目标对象,而不像值传递一样在函数作用域内建立变量的副本。

实例:

#include 
using namespace std; 
int exchange(int& a,int& b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
int x=1,y=2;
cout<<"x,y交换前的值分别为:"<<x<<" "<<y<<'\n'; 
exchange(x,y);
cout<<"x,y交换后的值分别为:"<<x<<" "<<y<<'\n'; 
return 0;
}

运行结果为:

x,y交换前的值分别为:1 2
x,y交换后的值分别为:2 1

引用的威力和指针相当,且可读性比指针好。

3.2.小结:

  1. 在C++中,引用类型主要作为函数参数,以增加函数传递数据的功能,更加灵活。

  2. 引用作为函数形参时,调用函数后,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。

  3. 把引用作为参数传递的函数,调用时不能传入常量。

4.用引用返回多个值

我们知道,函数只能返回一个值。但是我们可以通过在函数参数里增加若干个对象的引用,这能实现改变多个对象的值的功能,相当于让函数返回多个值。

实例:

#include 
using namespace std; 
void func(int n,int& a,int& b)
{
    a = n*n;
    b = n*n*n;
}
int main()
{
int var,square,cube;
cout<<"请输入10以内的整数:\n";
cin>>var;
func(var,square,cube);
cout<<var<<"的平方为:"<<square<<'\n'
    <<var<<"的立方为:"<<cube; 
return 0;
}

运行结果:

请输入10以内的整数:
4
4的平方为:16
4的立方为:64

5.常量引用

我们在引用的最前面加上关键字const便成了常量引用

我们在函数的参数中使用引用,但如果此时我们不想让引用的对象被修改了,就可以使用const关键字进行修饰引用,这会使实参不被修改。

举例:

C++学习笔记(十九):有关引用的总结_第1张图片

上述代码表明,我们对引用使用const修饰后,其作用就是使目标成为const常量

6.引用作为函数返回值

6.1.返回引用

我们知道,函数在返回值时,会产生一个值的副本。但是,我们用引用返回值时,不会生成值的副本。/这是用返回引用的一大好处。

语法:在函数名前加上&运算符。

  • 即:数据类型 &函数名(形参列表){ 函数体 }

引用返回的形式一共有4种,代码如下:

#include 
using namespace std; 
const double PI = 3.141592;
double temp;
double get_girth_1(double r)
{
    temp = 2*PI*r;
    return temp;
}
double& get_girth_2(double r)
{
    temp = 2*PI*r;
    return temp;
}
int main()
{
  double  girth_a = get_girth_1(3.0); //方式1 
//double& girth_b = get_girth_1(3.0); //方式2 错误 
  double  girth_c = get_girth_2(3.0); //方式3 
  double& girth_d = get_girth_2(3.0); //方式4 
cout<<girth_a<<'\n'
    <<girth_c<<'\n'
    <<girth_d;
return 0;
}

运行结果如下:

18.8496
18.8496
18.8496

说明:

在这四种引用返回的形式中,方式2有误,其余三种方式的运行结果是一样的,但其实它们在内存中的情况是不同的。其中,变量temp是全局变量,存储在全局数据区data中。主函数main(),函数get_girth_1()get_girth_2()的数据都存储在栈区stack中。


6.1.1.方式1解析

方式1是一般的函数返回值方式,返回全局变量temp时,C++会创建临时变量,并将temp的值复制给这个临时变量。返回主函数后,语句double girth_a = get_girth_1(3.0);把临时变量的值复制给变量girth_a。这是合法的。

6.1.2.方式2解析

  • 方式2与方式1类似,也把temp的值复制给某个临时变量,但在返回主函数后,临时变量的值却赋值给了一个double类型的引用,double& girth_b = get_girth_1(3.0),很显然,引用girth_b以某个临时变量来初始化,这是错误的。

  • 如果非要以返回值来初始化一个引用,则需要先创建一个变量来接收临时变量的值,再把这个变量赋值给引用,比如:

double x = get_girth_1(3.0);
double& girth_b = x;

6.1.3.方式3解析

方式3中的函数get_girth_2()的返回值不产生副本,所以直接将全局变量temp的值返回给主函数。即左值girth_c直接从全局变量temp那得到赋值。这就避免了临时变量的产生,使程序的执行效率和空间利用得到了提升。

6.1.4.方式4解析

方式4返回了一个引用,这也不产生任何返回值的副本。在主函数中也用了double类型的引用girth_d去接收返回值。这使得girth_d成为全局变量temp的引用(别名),由于temp是全局变量,这使得在引用girth_d生命期内temp的值都有效。

6.2.注意事项

注意事项如下:

  1. 我们不能返回局部变量的引用。 这是因为局部变量会在函数返回后被销毁,被返回的引用会成为"无所指"的引用
  2. 不能返回函数内部new分配的内存的引用。 如果被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放造成内存泄漏
  3. 可以返回类成员的引用,但最好用const修饰。 这是因为当对象的属性与某些规则有关时,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在某种规则之下。即其它对象只能获得某种属性的常量引用,那么对该属性的单纯赋值就不会破坏规则的完整性。

文末备注参考书:《C++程序设计教程》----钱能 著


好了,引用的总结就到这里,下一节我们看C++中的类

你可能感兴趣的:(【C++学习笔记】,学习,c++,开发语言)