C++:引用(reference)

在C++中,引用(reference)是一种别名,可以用来避免值传递带来的开销,并直接操作原始变量。以下是一些引用方法的使用案例,包括引用作为函数参数、返回值和类成员。

引用作为函数参数

通过引用传递参数可以避免复制参数,并且可以在函数内部修改原始变量。

#include <iostream>

void increment(int &n) {
    n++;
}

int main() {
    int a = 5;
    increment(a);
    std::cout << "Value of a after increment: " << a << std::endl;  // Output: 6
    return 0;
}

在这里插入图片描述

引用作为函数返回值

函数可以返回一个引用,从而可以直接操作原始变量。

#include <iostream>

int& getElement(int arr[], int index) {
    return arr[index];
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    getElement(arr, 2) = 10;  // 修改原数组
    std::cout << "Value of arr[2]: " << arr[2] << std::endl;  // Output: 10
    return 0;
}

在这里插入图片描述

常量引用

常量引用用于保护引用的变量不被修改,同时避免了传值的开销。

#include <iostream>

void myprint(const int &n) {
    std::cout << "Value: " << n << std::endl;
}

int main() {
    int a = 5;
    myprint(a);
    return 0;
}

在这里插入图片描述

引用作为类成员

引用可以作为类的成员变量来使用,不过需要在初始化列表中进行初始化。

#include <iostream>

class Example {
private:
    int &ref;

public:
    Example(int &r) : ref(r) {}

    void set(int value) {
        ref = value;
    }

    void print() const {
        std::cout << "Value: " << ref << std::endl;
    }
};

int main() {
    int a = 5;
    Example ex(a);
    ex.print();  // Output: 5
    ex.set(10);
    ex.print();  // Output: 10
    std::cout << "Value of a: " << a << std::endl;  // Output: 10
    return 0;
}

在这里插入图片描述
头文件 Example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

#include <iostream>

class Example {
private:
    int &ref;

public:
    Example(int &r);

    void set(int value);
    void print() const;
};

#endif // EXAMPLE_H

源文件 Example.cpp

#include "Example.h"

Example::Example(int &r) : ref(r) {}

void Example::set(int value) {
    ref = value;
}

void Example::print() const {
    std::cout << "Value: " << ref << std::endl;
}

主程序文件 main.cpp

#include "Example.h"

int main() {
    int a = 5;
    Example ex(a);
    ex.print();  // Output: 5
    ex.set(10);
    ex.print();  // Output: 10
    std::cout << "Value of a: " << a << std::endl;  // Output: 10
    return 0;
}

引用用于交换函数

引用可以用于实现交换两个变量值的函数。

#include <iostream>

void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5, y = 10;
    std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
    swap(x, y);
    std::cout << "After swap: x = " << x << ", y = " << y << std::endl;
    return 0;
}

在这里插入图片描述

  • 引用介绍
    (1)引用的经典案例:实现swap函数实战
    (2)引用定义和识别的关键:&符号,注意这里和取地址一毛钱关系都没有
    (3)引用符号(注意我没说变量)在定义时必须同时初始化,以后不能再另外赋值,只能使用
  • 引用和指针的对比
    (1)指针在C和C++中都有,且使用方法和实现本质完全相同;引用只有C++可用
    (2)引用可以理解为功能弱化、安全性增强的低配版指针
    (3)引用能做的事指针都能做,但指针能做的事儿引用不一定能做
    (4)引用是它指向变量的“别名”,这个是从引用的使用效果角度讲的,对熟悉指针的人反而不好理解“别名”这个词
    (5)引用比指针弱的地方就是一个引用定义时绑定了一个变量,后面没法改了
    (6)引用比指针强的地方也是没法改,所以不存在"野指针"问题,更安全
    (7)引用主要用在函数传参和返回值

引用的本质剖析

  • 引用可以加const修饰
    (1)const int &b = a; 表示b是a的const别名,无法通过b修改a了
    (2)主要用在函数形参中,告诉大家该函数内部不会修改实参的值。用在某些时候我们有一个非const类型的变量,但是我们在某个函数调用的过程中,不希望变量的值在函数内部被修改,这时候就可以用const引用来传参。

头文件 StringCompare.h

#ifndef STRINGCOMPARE_H
#define STRINGCOMPARE_H

#include <string>

class StringCompare {
public:
    static int compare(const std::string &str1, const std::string &str2);
};

#endif // STRINGCOMPARE_H

源文件 StringCompare.cpp

#include "StringCompare.h"
#include <cstring>  // 包含 strcmp 函数的头文件

int StringCompare::compare(const std::string &str1, const std::string &str2) {
    return strcmp(str1.c_str(), str2.c_str());
}

主程序文件 main.cpp

#include <iostream>
#include "StringCompare.h"

int main() {
    std::string str1 = "hello";
    std::string str2 = "world";
    std::string str3 = "hello";

    int result1 = StringCompare::compare(str1, str2);
    int result2 = StringCompare::compare(str1, str3);

    std::cout << "Comparison result (str1 vs str2): " << result1 << std::endl; // Output: < 0 (negative value)
    std::cout << "Comparison result (str1 vs str3): " << result2 << std::endl; // Output: 0

    return 0;
}

在这里插入图片描述

  • 引用和sizeof运算符
    (1)sizeof引用得到的不是引用本身的大小,而是引用指向的目标变量的大小
    (2)在struct或class中定义一个引用,再sizeof整个struct或class就会不一样

头文件 TestSize.h

#ifndef TESTSIZE_H
#define TESTSIZE_H

class TestSize {
public:
    static void printSize(int &ref);
    static void printArraySize(int (&arr)[5]);
};

#endif // TESTSIZE_H

源文件 TestSize.cpp

#include "TestSize.h"
#include <iostream>

void TestSize::printSize(int &ref) {
    std::cout << "Size of reference: " << sizeof(ref) << " bytes" << std::endl;
    std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
}

void TestSize::printArraySize(int (&arr)[5]) {
    std::cout << "Size of array: " << sizeof(arr) << " bytes" << std::endl;
    std::cout << "Size of array element: " << sizeof(arr[0]) << " bytes" << std::endl;
    std::cout << "Number of elements in array: " << sizeof(arr) / sizeof(arr[0]) << std::endl;
}

主程序文件 main.cpp

#include <iostream>
#include "TestSize.h"

int main() {
    int a = 10;
    int arr[5] = {1, 2, 3, 4, 5};

    std::cout << "Testing size of reference and int:" << std::endl;
    TestSize::printSize(a);

    std::cout << "\nTesting size of array:" << std::endl;
    TestSize::printArraySize(arr);

    return 0;
}

在这里插入图片描述

typedef struct {
  int age;
  int &age1;
  char sex;
  char &sex1;
  double height;
  double &height1;
} Person;
  Person *per;
  std::cout << "Size of int age: " << sizeof(int) << " bytes" << std::endl;
  std::cout << "Size of char sex: " << sizeof(char) << " byte" << std::endl;
  std::cout << "Size of double height: " << sizeof(double) << " bytes"
            << std::endl;
  std::cout << "Size of Person struct: " << sizeof(Person) << " bytes"
            << std::endl;
  std::cout << "sizeof(per->age): " << sizeof(per->age) << " bytes"
            << std::endl;
  std::cout << "sizeof(per->age1): " << sizeof(per->age1) << " bytes"
            << std::endl;
  std::cout << "sizeof(per->height): " << sizeof(per->height) << " bytes"
            << std::endl;
  std::cout << "sizeof(per->height1): " << sizeof(per->height1) << " bytes"
            << std::endl;

  std::cout << "sizeof(per->sex): " << sizeof(per->sex) << " bytes"
            << std::endl;
  std::cout << "sizeof(per->sex1): " << sizeof(per->sex1) << " bytes"
            << std::endl;
4 (age) + 4 (age1) + 1(sex) + 1 (sex1) + 8 (height) +8(height1) = 26 字节

在这里插入图片描述
但是,实际上结构体 Person 的大小是 48 字节,这可能涉及到了编译器的内存对齐和填充策略。编译器通常会在结构体的成员之间插入填充字节,以确保每个成员都按照特定的对齐方式放置,从而提高访问速度和效率。因此,结构体的大小可能大于所有成员大小的总和。
引用成员的大小:
对于引用成员 per->sex1,尝试获取其大小通常是不允许的,因为引用在 C++ 中是一种语义上的概念,而不是真正占用内存空间的实体。因此,sizeof(per->sex1) 的结果可能会出现编译器报错或返回不可预测的值。

  • 引用的本质是const指针
    (1)int &b = a; 类似于 int * const b = &a;
    (2)C++标准并没有规定引用是否占用内存空间,但是大多数编译器都把引用实现为const指针,所以大部分编译器中引用也是要占内存空间的
    (3)引用是天然const的,所以定义时必须初始化指向变量,否则就没意义了
    (4)引用本质是指针,是地址,所以才能实现传址调用的效果
    总结:引用就是指针在定义时增加了把指针变量本身const化

总结

理解引用本质,熟悉使用方法

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

li星野

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值