【c++】cpp之引用

目录

(1)普通引用

1.引用的概念

2.引用与函数形参

3.引用与指针比较

4.引用的本质

5.结构体中有普通引用时占内存空间吗?

6.函数返回值是引用

7.指针引用与二级指针

(2)const引用

1.常引用的含义

2.对字面量的普通引用和常引用

3.常量引用是否占内存空间?


(1)普通引用

1.引用的概念

变量名(标识符)回顾

  • 变量名实质上是一段连续存储空间的别名,是一个标号(门牌号)
  • 程序中通过变量来申请并命名内存空间
  • 通过变量的名字可以使用存储空间

引出问题:对一段连续的内存空间只能取一个别名吗?

引用概念

  • 引用可以看作一个已定义变量的别名,与原变量内存地址相同
  • 引用的语法:Type &name = var;
#include <iostream>

using namespace std;

int main()
{
    int a = 1;
    int &b = a; //引用,b就是a的别名

    b = 9;
    cout << a << endl; // 9

    a = 99;
    cout << b << endl; // 99

    cout << &a << "," << &b << endl;  // 0x7ffece407cb4,0x7ffece407cb4
    //可以看到地址是相同的

    return 0;
}

2.引用与函数形参

  • 普通引用在声明时必须用其它的变量进行初始化
  • 引用作为函数参数声明时不进行初始化
  • 引用做函数形参时,操作形参等价于操作实参
#include <iostream>

using namespace std;

// 2.函数形参无需初始化
void swap(int &a, int &b)
{
    int c = 0;
    c = a;
    a = b;
    b = c;
}

int main()
{
    // 1.普通引用需初始化
    int x = 1;
    int &g = x;
    // int &c; //这句会报错,因为普通引用,必须要初始化

    int y = 100;
    swap(x, y);
    
    cout << x << " " << y << endl; //100 1
    // swap函数形参是引用
    // 因此函数内部进行改值操作后,x和y的值发生了变化

    return 0;
}

3.引用与指针比较

  • 引用的本质是指针。
  • 引用作为其它变量的别名而存在,因此在一些场合可以代替指针。
  • 引用相对于指针来说具有更好的可读性和实用性。

例子①:

#include <iostream>

using namespace std;

void myswap01(int a, int b) //不可以对实参进行交换
{
    int c = 0;
    c = a;
    a = b;
    b = c;
}

void myswap02(int *a, int *b) //可以对实参进行交换
{
    int c = 0;
    c = *a;
    *a = *b;
    *b = c;
}


void myswap03(int &a, int &b) //可以对实参进行交换
{
    int c = 0;
    c = a;
    a = b;
    b = c;
}

int main()
{
    int x, y;
    x = 10;
    y = 20;

    myswap01(x, y);
    printf("x:%d , y:%d \n", x, y); //x:10 , y:20

    myswap02(&x, &y);
    printf("x:%d , y:%d \n", x, y); //x:20 , y:10

    // a就是x的别名 b就是y的别名
    myswap03(x, y);
    printf("x:%d , y:%d \n", x, y); //x:10 , y:20
    
    return 0;
}

例子②:

#include <iostream>

using namespace std;

struct Teacher
{
    char name[64];
    int age;
};

// 用指针
void changeT1(Teacher *pT)
{
    // cout << pT->age << endl;
    pT->age = 100;
}

// pT是t1的别名
void changeT2(Teacher &pT)
{
    // cout << pT.age << endl;
    pT.age = 33;
}

// pT和t1的是两个不同的变量
void changeT3(Teacher pT)
{
    // cout << pT.age << endl;
    pT.age = 45; //只会修改pT变量 ,不会修改t1变量 //因为是形参
}

int main()
{
    Teacher t1;
    t1.age = 18;

    changeT1(&t1);
    printf("t1.age:%d \n", t1.age); // 100

    changeT2(t1); // pT是t1的别名
    printf("t1.age:%d \n", t1.age); // 33

    changeT3(t1); // pT是形参 ,t1 copy一份数据 给pT
    printf("t1.age:%d \n", t1.age); // 33

    return 0;
}

4.引用的本质

引用在C++中的内部实现是一个指针常量

#include <iostream>

using namespace std;

void modifyA1(int &a1)
{
    a1 = 100;
}
void modifyA2(int *const a1)
{
    *a1 = 200;
}

int main()
{
    int a = 10;
    modifyA1(a);
    printf("a=%d \n", a); //a=100

    a = 10;
    modifyA2(&a);
    printf("a=%d \n", a); //a=200

    return 0;
}

5.结构体中有普通引用时占内存空间吗?

答案:占

#include <iostream>

using namespace std;

typedef struct Teacher1
{
    int &a;
    int &b;
}Teacher1;

typedef struct Teacher2
{
    int x;
    int y;
    int &a;
    int &b;
}Teacher2;


int main()
{
    printf("%d\n", sizeof(Teacher1));  // 16
    printf("%d\n", sizeof(Teacher2));  // 24

    // 可以看出引用会占用内存

    //int x=1, y=2;
    //Teacher1 t1 = {x, y};
  
    return 0;
}

6.函数返回值是引用

当函数返回值为引⽤时

  • 若返回栈变量:不能作为左值使⽤,不能成为其它引⽤的初始值,也不要当作右值使⽤,容易出错,最好不要把栈变量的引⽤当作返回值
  • 若返回静态变量或全局变量:既可作为右值使⽤,也可作为左值使⽤,可以成为其他引⽤的初始值。
    • 当作右值时,返回该静态变量或全局变量的值
    • 当作左值时,相当于就是返回的该静态变量或全局变量

示例代码理解

#include <iostream>

using namespace std;

int getA1()
{
    static int a = 10;
    a++;
    return a;
}

int &getA2()
{
    static int a = 10;
    a++;
    return a;
}

// 若返回静态变量或全局变量
// 可以成为其他引用的初始值
// 即可作为右值使用,也可作为左值使用
int main()
{
    int a1 = 0;
    int a2 = 0;

    // 1.返回静态变量,当做右值
    a1 = getA1();
    cout << a1 << endl; //11

    a2 = getA1();
    cout << a2 << endl; //12

    a1 = 100;
    cout << a2 << endl; //12

    // 2.返回静态变量的引用,当做右值
    int &a3 = getA2();
    cout << a3 << endl; //11
    a3 = 100;
    int &a4 = getA2();
    cout << a4 << endl; //101


    // 3.返回静态变量的引用,当做左值
    getA2() = 1000;
    cout << a3 << endl; //1000
    cout << a4 << endl; //1000

    return 0;
}

7.指针引用与二级指针

普通引用对标一级指针

指针引用对标二级指针

#include <iostream>

struct Teacher
{
    char name[64];
    int age;
};

// 二级指针做形参操作一级指针
int changeAge(Teacher **myp) 
{
    *myp = new Teacher;
    (*myp)->age = 100;

    return 0;
}


// 指针的引用
int changeAge2(Teacher *&myp)
{
    myp = new Teacher;
    myp->age = 18;

    return 0;
}


int main()
{
    Teacher *p = NULL;
    changeAge(&p);
    std::cout << p->age << std::endl;  // 100

    delete p;

    changeAge2(p);
    std::cout << p->age << std::endl;  // 18
    
    delete p;

    return 0;
}

(2)const引用

1.常引用的含义

常引⽤:cost int &a = b;

作用含义:不能通过引⽤来改变那个地址的值,常引⽤让别名只拥有只读属性。但是可以通过指向常引用的指针来修改对应地址的值

常引用通常用在函数形参中,让引用只有只读属性。

示例代码理解:

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

class teacher
{
public:
    char name[20];
    int age;
    void set_name(char *name)
    {
        strcpy(this->name, name);
    }
    void set_age(int age)
    {
        this->age = age;
    }
};

void printTeacher(const teacher &teaName)
{
    // teaName.age = 100; //非法,因为const参数,让teaName只有只读属性
    cout << "teaName.age = " << teaName.age << endl;
    cout << "teaName.name = " << teaName.name << endl;
}

int main()
{
    int a = 10;
    const int &b = a;
    std::cout << b << std::endl;  // 10

    a = 11;
    std::cout << b << std::endl;  // 11

    // 1.不用通过常引用变量来修改对应地址的值
    // b = 100; //非法,因为常引用
    // std::cout << b << std::endl;

    // 2.但是可以通过指向常引用的指针来修改对应地址的值
    int  *p = (int *)&b;
    *p = 100;
    std::cout << a << std::endl;  // 100
    std::cout << b << std::endl;  // 100

    // 3.const让引用做函数参数时只有可读属性
    teacher mytea;
    strcpy(mytea.name, "tom");
    mytea.set_age(20);

    printTeacher(mytea);

    return 0;
}

2.对字面量的普通引用和常引用

  • 对字面量的普通引用,比如【int &c = 10;】,会error,因为字面量的地址是固定的,如果不加const编译失败
  • 对字面量的常引用,比如[【const int &a = 10;】,ok的,因为字面量的地址固定正好与const的作用达成一致
#include <iostream>
#include <cstring>
using namespace std;


int main()
{
    //1.对字面量的普通引用,会error
    //int &c = 10; //普通引用,引用一个字面量
    //int &a1 = 19; 
    //会报错,因为字面量的地址是固定的,如果不加const编译失败

    // 2.const变量只有只读属性
    const int b = 10; //c++编译器把a放在符号表中
    std::cout << &b << std::endl;  // 0x7ffcd870aed0
    // b = 100;  // error,因为b是只读属性

    // 3.对字面量的常引用, ok的
    const int &a = 10;  
    std::cout << &a << std::endl; // 0x7ffcd870aed4  // c++编译器 会 分配内存空间


    return 0;
}

3.常量引用是否占内存空间?

  • ⽤变量对const引⽤初始化,const引⽤分配内存空间了吗? 没有,就是别名
  • ⽤常量对const引⽤初始化,const引⽤分配内存空间了吗? 有,分配了内存空间
#include <iostream>

int main()
{
    int a = 10;
    const int &b = a;
    std::cout << &a << "," << &b << std::endl;  // 0x7fff40a1c448,0x7fff40a1c448
    // 相等的,说明用变量对常量引用初始化的话,不会额外开辟内存空间

    const int &c = 10;
    std::cout << &c << std::endl; // 0x7fff40a1c44c
    // 存在地址空间,说明⽤字面量对常量引⽤初始化,会分配内存空间

    return 0;
}

end

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值