【C++第二阶段】引用-语法 & 注意事项 & 做函数参数 & 本质 & 常量引用

引用

引用基本语法

引用,就是对同一个地址起个别名。

同一块地址,有不同的名称,就像同一个人,有不同的昵称。

所以,修改时还是两者修改都一样。

示例代码:

void cite(){
    int a = 10;
    int &b = a;
    cout<<"a = "<<a<<endl;
    cout<<"b = "<<b<<endl;

    cout<<"a 的地址为:"<<&a<<endl;
    cout<<"b 的地址为:"<<&b<<endl;

    a = 20;
    cout<<"修改a之后——————"<<endl;

    cout<<"a = "<<a<<endl;
    cout<<"b = "<<b<<endl;

    cout<<"a 的地址为:"<<&a<<endl;
    cout<<"b 的地址为:"<<&b<<endl;

    b = 30;
    cout<<"修改b之后——————"<<endl;

    cout<<"a = "<<a<<endl;
    cout<<"b = "<<b<<endl;

    cout<<"a 的地址为:"<<&a<<endl;
    cout<<"b 的地址为:"<<&b<<endl;

}

运行结果:

image-20240125232551120

出现乱码的问题,通过这个方法解决。

引用注意事项

①引用与变量的关系是多对一,一个引用只能绑定一个变量,但一个变量可以绑定多个引用。

②引用必须初始化,否则会报错。

③引用后其他变量再赋值,此时代码说明并不是与其他变量进行了绑定,而是其他变量的值赋给当前的引用。

示例代码:

void cite_notice(){
    cout<<"\t引用注意事项\t"<<endl;
    int a = 10;
    int &b = a;
    int c = 20;
    int &A = a;
//    注意事项①,引用:变量 =n:1,多个引用可以指向同一个变量,但一个引用不能更改其指向的变量。
    cout<<"各个变量及其地址分别如下。"<<endl;

    cout<<"a = "<<a<<",引用&b=a中,b="<<b<<",引用&A=a中,A="<<A<<"。"<<endl;
    cout<<"a地址 = "<<&a<<",引用&b=a中,b地址="<<&b<<",引用&A=a中,A地址="<<&A<<"。"<<endl;
    cout<<"c = "<<c<<",c地址 = "<<&c<<"。"<<endl;
//    注意事项②,引用如果出现b = c;的代码,其含义是c的值赋值给了b,而不是b指向了c。
    cout<<endl;
    b = c;
    cout<<"b = c 后,各个变量的值和地址分别如下。"<<endl;

    cout<<"a = "<<a<<",引用&b=a中,b="<<b<<",引用&A=a中,A="<<A<<"。"<<endl;
    cout<<"a地址 = "<<&a<<",引用&b=a中,b地址="<<&b<<",引用&A=a中,A地址="<<&A<<"。"<<endl;
    cout<<"c = "<<c<<",c地址 = "<<&c<<"。"<<endl;
}

运行结果:

image-20240125235711885

引用做函数参数

如果是全局变量,再用值传递的方式是否可以交换值?为什么?——答案是不可以。

实验代码:

	cout<<"原先的 a = "<<a<<",b = "<<b<<"。"<<endl;
    SwapByValue(a , b);//ab的值定义在全局
    cout<<"按照值传递后的 a = "<<a<<",b = "<<b<<"。"<<endl;


void SwapByValue(int first_value , int second_value){
    int temp_value = second_value;
    second_value = first_value;
    first_value = temp_value;
}

作用:函数传参数,可以利用引用让形参修饰实参。

优点:可以简化指针修改实参。

总结:通过引用参数产生的效果同地址传递是一样的,引用语法更加清楚简单。

引用的名称可以和原来的名称一致。引用按照我的理解就是一块地址起了个名字,并且不需要解析(指针地址中的解引用)。

三种方法进行交换。

#include<iostream>
#include<string>
using namespace std;

void SwapByValue(int first_value , int second_value){
    int temp_value = second_value;
    second_value = first_value;
    first_value = temp_value;
}

void SwapByAddress(int * first_address , int * second_address){
//    这里的temp_value仍然是整数类型,因为传入的是地址,地址需要解引用取值,是对其值操作,所以用整数类型
    int temp_value = *second_address;
    *second_address = *first_address;
    *first_address = temp_value;
}

void SwapByCite(int &first_cite , int &second_cite){
//    这里用的是引用方式来交换值,传入的是引用,也就是一个值的地址名。但又可以直接对值操作。
    int temp_value = second_cite;
    second_cite = first_cite;
    first_cite = temp_value;
}
int main(){

    int a = 10;
    int b = 20;
//    把值作为参数传入到方法中
    cout<<"原先的 a = "<<a<<",b = "<<b<<"。"<<endl;
    SwapByValue(a , b);
    cout<<"按照值传递后的 a = "<<a<<",b = "<<b<<"。\n"<<endl;
    
    int a_address = 10;
    int b_address = 20;
//    把地址作为参数传入到方法中
    cout<<"原先的 a_address = "<<a_address<<",b_address = "<<b_address<<"。"<<endl;
    SwapByAddress(&a_address , &b_address);
    cout<<"按照地址传递后的 a_address = "<<a_address<<",b_address = "<<b_address<<"。\n"<<endl;

    int a_cite = 10;
    int b_cite = 20;
//    把引用作为参数传入到方法中
    cout<<"原先的 a_cite = "<<a_cite<<",b_cite = "<<b_cite<<"。"<<endl;
    SwapByCite(a_cite , b_cite);
    cout<<"按照地址传递后的 a_cite = "<<a_cite<<",b_cite = "<<b_cite<<"。"<<endl;
    
    return 0;
}

运行结果如下:

image-20240126104355382

引用做函数返回值

函数返回值可以是引用,但是返回的变量不能是局部变量引用,同样地不能返回局部变量/局部变量的地址,因为返回这些东西,它们的生命周期太短,会被系统销毁,导致会取乱值。

示例代码:

int & example = ReturnLocalCite();
cout<<"返回局部类型的变量引用,对应值为:"<<  example<<"。"<<endl;
cout<<"返回局部类型的变量引用,对应值为:"<<  example<<"。"<<endl;
cout<<"返回局部类型的变量引用,对应值为:"<<  example<<"。"<<endl;


int & ReturnLocalCite(){
    int local_variable = 10;
    return local_variable;
}

运行结果:没有显示,手动停止的。

image-20240126110400794

调试结果:

image-20240126110512174

函数返回值为引用时,可以作为左值使用——也就是对函数赋值。

示例代码:

#include<iostream>
#include<string>
using namespace std;

int & ReturnGlobalCite(){
    cout<<"\n函数返回值为引用时,可以作为左值的示例函数。"<<endl;
    static int global_variable = 10;
    return global_variable;//这里为什么不返回&global_variable?因为这样做返回的就是地址了
}

int main(){
//用global_example 定义为int类型的引用,接收函数返回值。
    int & global_example = ReturnGlobalCite();
    cout<<"返回全局类型的变量引用,对应值为:"<<global_example<<"。"<<endl;
    cout<<"返回全局类型的变量引用,对应值为:"<<global_example<<"。"<<endl;

    ReturnGlobalCite() = 1000;
    cout<<"函数返回值为引用时,左值赋值为1000,此时ReturnGlobalCite() = "<<ReturnGlobalCite()<<"。"<<endl;
    cout<<"函数返回值为引用时,左值赋值为1000,此时引用global_example = "<<global_example<<"。"<<endl;

}

运行结果:

image-20240126111425689

通过运行结果可以发现,函数返回值为引用时,可以对其进行复制,且函数返回值赋值给的其他变量也会相应地更改值。

引用本质

引用的本质就是指针常量,首先它是个指针,其次这个指针是常量的,按照我理解就是静态的,指向一个地址后,就不能再更改了。所以,回顾之前的代码。新建一个引用:

int a = 10;int &A = a;就等于int * const A = &a;,而对a赋值A=20;就等于*A=20;

总结:C++推荐使用引用,因为更简单,其他的都由编译器完成了。

常量引用

基于引用是一个指针常量,看常量引用说明什么问题。

①引用只能指向一个确定的内存地址,比如

int a = 10;
int &A = a;

这是合法的,因为此时A指向a。但如果int &A = 10;不行,因为10在内存空间中还没有确定的位置,没有确定的位置也就意味着指针常量不能指向它,因为指针常量指向的是一个确定的地址,并且不能改变。所以,如果在前面加上const关键字,就可以了,此时的工作原理是,编译器给10(或其他任意的常量)起了一个变量名,这个变量名开发者不知道,但却能够使得const int &A = 10;正常执行,因为此时变成了静态指针,指针只能指向这块内存,并且这块内存的值不能修改。

②既如此,它的使用环境一般体现在哪里?体现在不修改其值的情况中。比如有函数只想做打印操作,不想更改其值。就可以新建一个变量,函数的参数值为const常量引用,这样如果在函数体内部出现了修改的操作,就会报错。

示例代码:

#include<iostream>
#include<string>
using namespace std;

void ConstantCite(const int &constant){
    cout<<"该常量值为:"<<constant<<"。"<<endl;
}

int main(){
	const int &tant = 10;
	ConstantCite(tant);
	return 0;
}

可以看到,函数参数值为const修饰的引用,不能再在函数体内部以及传递参数时修改其值。同时定义的tant是引用,也不能修改值。

函数的默认参数

函数的默认参数意为在函数定义或声明时就对参数赋值。需要注意两点,①函数参数在声明或者定义时,只能存在于一种情况,要么声明时赋值默认参数,要么定义时声明默认参数,二选一,否则编译器会报错。

以下为第一种情况的说明代码及情况。

#include <iostream>
#include <string>
#include"BlackHorseFunctions.h"
using namespace std;

int PlusVersion1(int a = 10 , int b );//这里就报错了

int main(){
    system("chcp 65001");
    cout<<PlusVersion1()<<endl;
    system("pause");

    return 0;
}
int PlusVersion1(int a=11  , int b=21 ){//这里值为多少无所谓,它会报错。
    return a+b;
}

情况:

====================[ 构建 | Section2Study | Debug ]==============================
“D:\SetUpSoftWare\JetBrain\Clion\CLion 2023.1.1\bin\cmake\win\x64\bin\cmake.exe” --build D:\Program\C++C\BlackHorseStudy\cmake-build-debug --target Section2Study -j 6
[1/2] Building CXX object CMakeFiles/Section2Study.dir/Section2Study.cpp.obj
FAILED: CMakeFiles/Section2Study.dir/Section2Study.cpp.obj
“D:\SetUpSoftWare\JetBrain\Clion\CLion 2023.1.1\bin\mingw\bin\g++.exe” -g -fdiagnostics-color=always -MD -MT CMakeFiles/Section2Study.dir/Section2Study.cpp.obj -MF CMakeFiles\Section2Study.dir\Section2Study.cpp.obj.d -o CMakeFiles/Section2Study.dir/Section2Study.cpp.obj -c D:/Program/C++C/BlackHorseStudy/Section2Study.cpp
D:/Program/C++C/BlackHorseStudy/Section2Study.cpp:27:5: error: default argument given for parameter 1 of ‘int PlusVersion1(int, int)’
27 | int PlusVersion1(int a =11 , int b =21){
| ^~~~~~~~~~~~
D:/Program/C++C/BlackHorseStudy/Section2Study.cpp:9:5: note: previous specification in ‘int PlusVersion1(int, int)’ here
9 | int PlusVersion1(int a = 10 , int b = 20);
| ^~~~~~~~~~~~
D:/Program/C++C/BlackHorseStudy/Section2Study.cpp:27:5: error: default argument given for parameter 2 of ‘int PlusVersion1(int, int)’
27 | int PlusVersion1(int a =11 , int b =21){
| ^~~~~~~~~~~~
D:/Program/C++C/BlackHorseStudy/Section2Study.cpp:9:5: note: previous specification in ‘int PlusVersion1(int, int)’ here
9 | int PlusVersion1(int a = 10 , int b = 20);
| ^~~~~~~~~~~~
ninja: build stopped: subcommand failed.

第二种情况,在给定函数默认参数时,有一个顺序关系,按照从左到右的顺序,如果左面的参数已赋初始值,那么紧随其后右边的参数也需要赋初始值,否则会报错。以下是第二种情况的说明代码及情况。

#include <iostream>
#include <string>
#include"BlackHorseFunctions.h"
using namespace std;

int PlusVersion1(int a = 10 , int b );//这里就报错了

int main(){
    system("chcp 65001");
    cout<<PlusVersion1()<<endl;
    system("pause");

    return 0;
}
int PlusVersion1(int a  , int b ){
    return a+b;
}

情况:====================[ 构建 | Section2Study | Debug ]==============================

“D:\SetUpSoftWare\JetBrain\Clion\CLion 2023.1.1\bin\cmake\win\x64\bin\cmake.exe” --build D:\Program\C++C\BlackHorseStudy\cmake-build-debug --target Section2Study -j 6
[1/2] Building CXX object CMakeFiles/Section2Study.dir/Section2Study.cpp.obj
FAILED: CMakeFiles/Section2Study.dir/Section2Study.cpp.obj
“D:\SetUpSoftWare\JetBrain\Clion\CLion 2023.1.1\bin\mingw\bin\g++.exe” -g -fdiagnostics-color=always -MD -MT CMakeFiles/Section2Study.dir/Section2Study.cpp.obj -MF CMakeFiles\Section2Study.dir\Section2Study.cpp.obj.d -o CMakeFiles/Section2Study.dir/Section2Study.cpp.obj -c D:/Program/C++C/BlackHorseStudy/Section2Study.cpp
D:/Program/C++C/BlackHorseStudy/Section2Study.cpp:9:35: error: default argument missing for parameter 2 of ‘int PlusVersion1(int, int)’
9 | int PlusVersion1(int a = 10 , int b );
| ~~~~^
D:/Program/C++C/BlackHorseStudy/Section2Study.cpp:9:22: note: …following parameter 1 which has a default argument
9 | int PlusVersion1(int a = 10 , int b );
| ~~~~^~~~~~
ninja: build stopped: subcommand failed.

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HelpFireCode

随缘惜缘不攀缘。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值