C++中引用

本文深入探讨了C++中引用的概念、应用以及与指针的区别,包括引用的声明方法、注意事项、引用在函数参数、返回值及常引用的使用,详细解释了引用作为函数参数的优势,以及引用与指针在内存管理、效率和安全性方面的对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是引用

引用:就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。

引用的声明方法类型标识符 &引用名=目标变量名

例:

char a;
char &ra=a; // 定义引用ra,它是变量a的引用,即别名

特别注意:

1、&不是求地址运算符,而是起标志作用,用来表示该变量是引用类型的变量。

2、引用的类型必须和其所绑定的变量的类型相同。

#include<iostream>
using namespace std;
int main(){
    double a=10.3;
    int &b=a; //错误,引用的类型必须和其所绑定的变量的类型相同
    cout<<b<<endl;
}

这里写图片描述

3、声明引用的同时必须对其初始化,否则系统会报错。

#include<iostream>
using namespace std;
int main(){
    int &a; //错误!声明引用的同时必须对其初始化
    return 0;
}

这里写图片描述

4、引用相当于变量或对象的别名,因此不能再将已有的引用名作为其他变量或对象的名字或别名。

5、引用不是定义一个新的变量或对象,因此内存不会为引用开辟新的空间存储这个引用。故:对引用求地址,就是对目标变量求地址。&value与&new_value相等

#include<iostream>
using namespace std;
int main(){
    int value=10;
    int &new_value=value;
    cout<<"value在内存中的地址为:"<<&value<<endl; // 对引用求地址,就是对目标变量求地址
    cout<<"new_value在内存中的地址为:"<<&new_value<<endl;
    return 0;
}

这里写图片描述

6、对数组的引用
语法:类型 (&引用名)[数组中元素数量]=数组名

#include<iostream>
using namespace std;
int main(){
    int a[3]={1,2,3};
    int (&b)[3]=a;//对数组的引用 
    cout<<&a[0]<<" "<<&b[0]<<endl;
    cout<<&a[1]<<" "<<&b[1]<<endl;
    cout<<&a[2]<<" "<<&b[2]<<endl;
    return 0;
}

这里写图片描述

7、对指针的引用
语法:类型 &引用名=指针名。可以理解为:(类型) &引用名=指针名,即将指针的类型当成类型*

#include<iostream>
using namespace std;
int main(){
    int a=10;
    int *ptr=&a;
    int *&new_ptr=ptr;
    cout<<&ptr<<" "<<&new_ptr<<endl;
    return 0; 
}

这里写图片描述

二、引用的应用

1、引用作为函数的参数

#include<iostream>
using namespace std;
void swap(int &a,int &b){//引用作为函数的参数
    int temp=a;
    a=b;
    b=temp; 
}
int main(){
    int value1=10,value2=20;
    cout<<"----------------------交换前----------------------------"<<endl;
    cout<<"value1的值为:"<<value1<<endl; 
    cout<<"value2的值为:"<<value2<<endl;
    swap(value1,value2); 
    cout<<"----------------------交换后----------------------------"<<endl;
    cout<<"value1的值为:"<<value1<<endl; 
    cout<<"value2的值为:"<<value2<<endl;
    return 0;
}

这里写图片描述

特别注意:

1.当用引用作为函数的参数时,其效果和用指针作为函数参数的效果相当。当调用函数时,函数中的形参就会被当成实参变量或对象的一个别名来使用,也就是说此时函数中对形参的各种操作实际上是对实参本身进行操作,而非简单的将实参变量或对象的值拷贝给形参

2.通常函数调用时,系统采用值传递的方式将实参变量的值传递给函数的形参变量。此时,系统会在内存中开辟空间用来存储形参变量,并将实参变量的值拷贝给形参变量,也就是说形参变量只是实参变量的副本而已;并且如果函数传递的是类的对象,系统还会调用类中的拷贝构造函数来构造形参对象。而使用引用作为函数的形参时,由于此时形参只是要传递给函数的实参变量或对象的别名而非副本,故系统不会耗费时间来在内存中开辟空间来存储形参。因此如果参数传递的数据较大时,建议使用引用作为函数的形参,这样会提高函数的时间效率,并节省内存空间。

3.使用指针作为函数的形参虽然达到的效果和使用引用一样,但当调用函数时仍需要为形参指针变量在内存中分配空间,而引用则不需要这样,故在C++中推荐使用引用而非指针作为函数的参数

4.如果在编程过程中既希望通过让引用作为函数的参数来提高函数的编程效率,又希望保护传递的参数使其在函数中不被改变,则此时应当使用对常量的引用作为函数的参数。

5.数组的引用作为函数的参数:C++的数组类型是带有长度信息的,引用传递时如果指明的是数组则必须指定数组的长度

#include<iostream>
using namespace std;
void func(int(&a)[5]){//数组引用作为函数的参数,必须指明数组的长度 
//函数体 
}
int main(){
    int number[5]={0,1,2,3,4};
    func(number); 
    return 0; 
 }

2、常引用

语法:const 类型 &引用名=目标变量名
常引用不允许通过该引用对其所绑定的变量或对象进行修改

#include<iostream>
using namespace std;
int main(){
    int a=10;
    const int &new_a=a;
    new_a=11;//错误!不允许通过常引用对其所绑定的变量或对象进行修改 
    return 0;
}

这里写图片描述

特别注意:

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

void func(string &str) {
    cout << str << endl;
}
int main() {
    func("Tomwenxing");
    return 0;
}

这里写图片描述

这是由于“Tomwenxing”会在系统中产生一个临时对象(string对象)来存储它们,而在C++中所有的临时对象都是const类型的,而上面的程序试图将const对象赋值给非const对象,这必然会使程序报错。如果在函数func的参数前添加const,则程序便可正常运行了。引用型参数应该在能被定义为const的情况下,尽量定义为const 。

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

void func(const string &str) {
    cout << str << endl;
}
int main() {
    func("Tomwenxing");
    return 0;
}

这里写图片描述

3、引用作为函数的返回值

语法:类型 &函数名(形参列表){ 函数体 }

特别注意:

1.引用作为函数的返回值时,必须在定义函数时在函数名前加&。

2.用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本。

//代码来源:RUNOOB
#include<iostream>
using namespace std;

float temp;
float fn1(float r) {
    temp = r*r*3.14;
    return temp;
}
float &fn2(float r) { //&说明返回的是temp的引用,换句话说就是返回temp本身
    temp = r*r*3.14;
    return temp;
}
int main() {
    float a = fn1(5.0); //case 1:返回值
    //float &b=fn1(5.0); //case 2:用函数的返回值作为引用的初始化值 [Error] invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'                           //(有些编译器可以成功编译该语句,但会给出一个warning) 
    float c = fn2(5.0);//case 3:返回引用
    float &d = fn2(5.0);//case 4:用函数返回的引用作为新引用的初始化值18     cout<<a<<endl;//78.5
    //cout<<b<<endl;//78.5
    cout << c << endl;//78.5
    cout << d << endl;//78.5
    return 0;
}

3.不能返回局部变量的引用。如上面的例子,如果temp是局部变量,那么它会在函数返回后被销毁,此时对temp的引用就会成为“无所指”的引用,程序会进入未知状态。

4.不能返回函数内部通过new分配的内存的引用。虽然不存在局部变量的被动销毁问题,但如果被返回的函数的引用只是作为一个临时变量出现,而没有将其赋值给一个实际的变量,那么就可能造成这个引用所指向的空间(有new分配)无法释放的情况(由于没有具体的变量名,故无法用delete手动释放该内存),从而造成内存泄漏。因此应当避免这种情况的发生。

5.当返回类成员的引用时,最好是const引用。这样可以避免在无意的情况下破坏该类的成员。

6.可以用函数返回的引用作为赋值表达式中的左值。

#include<iostream>
using namespace std;
int value[10];
int error=-1;
int &func(int n){
    if(n>=0&&n<=9)
        return value[n];//返回的引用所绑定的变量一定是全局变量,不能是函数中定义的局部变量 
    else
        return error;
}

int main(){
    func(0)=10;
    func(4)=12;
    cout<<value[0]<<endl; // 10
    cout<<value[4]<<endl; // 12
    return 0; 
}

三、引用的总结

1.在引用的使用中,单纯给某个变量取别名是毫无意义的,引用的目的主要用于在函数参数的传递中,解决大块数据或对象的传递效率和空间不如意的问题。

2.用引用传递函数的参数,能保证参数在传递的过程中不产生副本,从而提高传递效率,同时通过const的使用,还可以保证参数在传递过程中的安全性

3.引用本身是目标变量或对象的别名,对引用的操作本质上就是对目标变量或对象的操作。因此能使用引用时尽量使用引用而非指针

四、引用与指针的区别

1、指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。

2、引用在定义的时候必须进行初始化,并且不能够改变。指针在定义的时候不一定要初始化,并且指向的空间可变。(注:不能有引用的值为NULL)

3、有多级指针,但是没有多级引用,只能有一级引用。

4、指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用时引用的变量值加1)

5、sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。

6、引用访问一个变量是直接访问,而指针访问一个变量是间接访问。

参考文献:

  1. c++引用总结
  2. C++:引用的简单理解:文中的特别注意中的几点内容
  3. C++中引用与指针的区别
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值