C++基础(九)-引用

1. 引用概念

c++中新增了引用的概念,引用可以作为一个已定义变量的别名。引用是c++对c的重要扩充。在c/c++中指针的作用基本都是一样的,但是c++增加了另外一种给函数传递地址的途径,这就是按引用传递(pass-by-reference),它也存在于其他一些编程语言中,并不是c++的发明。

1.  变量名实质上是一段连续内存空间的别名,是一个标号(门牌号)

2. 程序中通过变量来申请并命名内存空间

3. 通过变量的名字可以使用存储空间

基本语法:

Type& ref = val;

注意事项:

1. &在此不是求地址运算,而是起标识作用。

2. 类型标识符是指目标变量的类型

3. 必须在声明引用变量时进行初始化。

4. 引用初始化之后不能改变。

5. 不能有NULL引用。必须确保引用是和一块合法的存储单元关联。

6. 建立对数组的引用。

 

//1. 认识引用
void test01(){
 
    int a = 10;
    //给变量a取一个别名b
    int& b = a; //int * const b = &a;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "------------" << endl;
    //操作b就相当于操作a本身
    b = 100;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "------------" << endl;
    //一个变量可以有n个别名
    int& c = a;
    c = 200;
    cout << "a:" << a << endl;
    cout << "b:" << b << endl;
    cout << "c:" << c << endl;
    cout << "------------" << endl;
    //a,b,c的地址都是相同的
    cout << "a:" << &a << endl;
    cout << "b:" << &b << endl;
    cout << "c:" << &c << endl;
}
//2. 使用引用注意事项
void test02(){
    //1) 引用必须初始化
    //int& ref; //报错:必须初始化引用
    //2) 引用一旦初始化,不能改变引用
    int a = 10;
    int b = 20;
    int& ref = a;
    ref = b; //不能改变引用
}

建立数组引用:

 //1. 建立数组引用方法一
    typedef int ArrRef[10];
    int arr[10];
    ArrRef& aRef = arr;
    for (int i = 0; i < 10;i ++){
        aRef[i] = i+1;
    }
    for (int i = 0; i < 10;i++){
        cout << arr[i] << " ";
    }
    cout << endl;
    //2. 建立数组引用方法二
    int(&f)[10] = arr;
    for (int i = 0; i < 10; i++){
        f[i] = i+10;
    }
    for (int i = 0; i < 10; i++){
        cout << arr[i] << " ";
    }
    cout << endl;

2. 指针引用

Type* pointer = NULL; 
Type*& = pointer;

例子:

struct Teacher{
    int mAge;
};
//指针间接修改teacher的年龄
void AllocateAndInitByPointer(Teacher** teacher){
    *teacher = (Teacher*)malloc(sizeof(Teacher));
    (*teacher)->mAge = 200; 
}
//引用修改teacher年龄
void AllocateAndInitByReference(Teacher*& teacher){
    teacher->mAge = 300;
}
void test(){
    //创建Teacher
    Teacher* teacher = NULL;
    //指针间接赋值
    AllocateAndInitByPointer(&teacher);
    cout << "AllocateAndInitByPointer:" << teacher->mAge << endl;
    //引用赋值,将teacher本身传到ChangeAgeByReference函数中
    AllocateAndInitByReference(teacher);
    cout << "AllocateAndInitByReference:" << teacher->mAge << endl;
    free(teacher);
}

对于c++中的定义那个,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址。

3. 常量引用

常量引用的定义格式:

const Type& ref = val;
常量引用注意:

1. 字面量不能赋给引用,但是可以赋给const引用

2. const修饰的引用,不能修改。

void test01(){
    int a = 100;
    const int& aRef = a; //此时aRef就是a
    //aRef = 200; 不能通过aRef的值
    a = 100; //OK
    cout << "a:" << a << endl;
    cout << "aRef:" << aRef << endl;
}
void test02(){
    //不能把一个字面量赋给引用
    //int& ref = 100;
    //但是可以把一个字面量赋给常引用
    const int& ref = 100; //int temp = 200; const int& ret = temp;
}

4. 引用是什么?

C++标准只规定了引用的语义,并没有规定引用如何实现。在大部分编译器中引用在C++内部是通过常量指针来实现,因此引用所占空间大小与指针大小相同,只是这个过程由编译器内部实现,对用户不可见。

//发现是引用,转换为 int* const ref = &a;
void testFunc(int& ref){
    ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
    int a = 10;
    int& aRef = a; //自动转换为int* const aRef = &a;这也能说明引用为什么必须初始化
    aRef = 20; //内部发现aRef是引用,自动帮我们转换为: *aRef = 20;
    cout << "a:" << a << endl;
    cout << "aRef:" << aRef << endl;
    testFunc(a);
    return EXIT_SUCCESS;
}

5.  引用优点

1. 引用不产生新的变量,减少形参与实参传递时的开销;

2. 由于引用可能导致实参随形参改变而改变,将其定义为常量引用可以消除这种副作用;

3. 不存在空值的引用,意味着我们在使用引用的时候不需要判断是否为NULL,一定程度上提升了效率;

4. 引用传递的性质像是指针传递,但是书写方式像值传递,引用的语法要比指针的语法更加易读和操作,指针能做的事情,引用也能做

了解: 在什么情况下使用指针,在什么情况下使用引用呢?

考虑到存在不指向任何对象的情况下;

可能在不同的情况下指向不同的对象,那么应该使用指针;

如果总是指向一个对象,且一旦初始化不会改变指向,那么应该用引用。

C++主张用引用传递取代地址传递的方式,因为引用语法容易且不易出错

很多同学可能有疑问,为什么C++中有了指针这种操作,还要提供引用。那么原因是C++为了兼容C语言,所以在C++中保留了C语言的指针,那引用是为了什么?在C++中支持运算符重载,那么引用设计的初衷是为了支持运算符重载。有些运算符在有些情况下不得不使用引用。一般情况下,指针和引用是可以直接互换的。

6. 什么时候使用引用

最常见看见引用的地方是在函数参数返回值中。如果从函数中返回一个引用,必须像从函数中返回一个指针一样对待。当函数返回值时,引用关联的内存一定要存在。

引用作为其它变量的别名而存在,因此在一些场合可以代替指针。

1. 不能返回局部变量的引用。

2. 函数当左值,必须返回引用。

//返回局部变量引用
int& TestFun01(){
    int a = 10; //局部变量
    return a;
}
//返回静态变量引用
int& TestFunc02(){
    static int a = 20;
    cout << "static int a : " << a << endl;
    return a;
}
int main(){
    //不能返回局部变量的引用
    int& ret01 = TestFun01();
    //如果函数做左值,那么必须返回引用
    TestFunc02();
    TestFunc02() = 100;
    TestFunc02();
 
    return EXIT_SUCCESS;
}

如果希望实参随着形参的改变而改变,那么使用一般的引用,如果不希望实参随着形参改变,那么使用常引用。

//const int& param防止函数中意外修改数据
void ShowVal(constint& param){
    cout << "param:" << param << endl;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值