【C++入门】缺省参数、函数重载与引用(下)

简介: 【C++入门】缺省参数、函数重载与引用

【C++入门】缺省参数、函数重载与引用(上):https://developer.aliyun.com/article/1496840


3.引用

3.1引用概念

  • 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
  • 它允许我们使用一个变量名来引用另一个变量的值,而不是创建一个新的变量
  • 引用通常用于传递函数的参数、返回函数值和简化语法

在C++中,我们可以通过以下方式定义一个引用:

type &ref = variable;//类型&  引用变量名(对象名) = 被引用实体

例如:

void TestRef()
 {
   int a = 10;
   int& ra = a;//<====定义引用类型
   printf("%p\n", &a);
   printf("%p\n", &ra);
 }

注意:引用类型必须和引用实体是同种类型的

再举个例子:

可以看到它们都是同一个地址,指向同一个变量

#include <iostream>

int main() {
    int num = 10;
    int &ref = num; // 引用num变量

    std::cout << "num: " << num << std::endl;
    std::cout << "ref: " << ref << std::endl;

    num = 20;
    std::cout << "num: " << num << std::endl;
    std::cout << "ref: " << ref << std::endl;

    ref = 30;
    std::cout << "num: " << num << std::endl;
    std::cout << "ref: " << ref << std::endl;

    return 0;
}
 

结果如下:

num: 10
ref: 10
num: 20
ref: 20
num: 30
ref: 30

可以看到,无论我们通过num还是ref来修改变量的值,都会影响到另一个变量的值,因为它们实际上是同一个变量的不同名称。

3.2引用特性

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
 {
  int a = 10;
    // int& ra;   // 该条语句编译时会出错
  int& ra = a;
  int& rra = a;
  printf("%p  %p  %p\n", &a, &ra, &rra);  
}

结果如下:

3.2常引用

C++中的常引用有两种情况:

  1. const引用:使用const关键字来修饰引用,表示引用的值不可修改。例如:
int x = 10;
const int& ref = x;

在上面的例子中,ref是一个对x的常引用,意味着不能通过ref来修改x的值。

  1. 常对象的引用:当引用一个常对象时,引用也必须是常引用。例如:
const int x = 10;
const int& ref = x;

在上面的例子中,ref是对常对象x的常引用。

常引用的作用是为了在不修改值的情况下使用对象,同时可以避免不必要的复制。常引用经常用于函数参数中,以便避免对实参进行复制。

指针和引用进行赋值和初始化时,权限可以缩小,但是不能放大

例如:

const int x = 10;
int& ref = x;//这是错误的,它放大了权限

在上面的例子中,原本的x被const修饰不能被改变数据,但是ref引用它时没有用const修饰说明可以被改动,放大了权限是不被接受的;这和指针是类似的:const int* p1 = NULL; int* p2 = p1;//这也是错误的


3.3使用场景

  • 做参数
void Swap(int& left, int& right)
 {
 int temp = left;
 left = right;
 right = temp;
 }

结果如下:

可以看到我们没有使用传递变量的指针给函数就改变了实参的数据;

使用引用作为函数参数可以避免复制大量的数据,提高函数的效率。同时,通过引用传递参数可以实现对原始数据的修改,而不需要借助指针来实现。

  • 做返回值

引用作为函数的返回值前提是:返回的值在调用完函数后不会被释放销毁

例如:

int& Count()
 {
 static int n = 0;
 n++;
 return n;
 }

n用static修饰为静态全局变量即使函数调用结束也不会被释放,所以可以用引用作为函数的返回值,这样就不需要再临时拷贝一份,减少了空间的消耗;

那么作为函数的返回值有什么作用呢?

举个例子:

#include<iostream>
#include<assert.h>
#define N 10
using namespace std;
//顺序表
typedef struct AY
{
  int arr[N];
  int size;
}AY;
int& PosAt(AY& ay, int x)
{
  assert(x < N);
  return ay.arr[x];
}
int main()
{
  AY ay;
  for (int i = 0; i < N; i++)
  {
    PosAt(ay, i) = i;//利用引用返回修改对应的值
  }
  for (int i = 0; i < N; i++)//打印
  {
    cout << PosAt(ay, i) << " ";
  }
  cout << endl;
  return 0;
}

结果如下:

从上面的函数我们可以知道引用返回除了可以减少拷贝还可以修改返回的对象;

总结:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

3.4引用和指针的区别


(1)在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间;而指针是保存着变量的地址的,是有独立的空间的;

例如:

int main()
 {
 int a = 10;
 int& ra = a;
 cout<<"&a = "<<&a<<endl;
 cout<<"&ra = "<<&ra<<endl;
 return 0;
 }

结果如下:

通过上述例子我们发现引用和原来的变量的地址是一样的;

(2)在底层实现上实际是有空间的,因为引用是按照指针方式来实现的;

例如:

#include<iostream>
using namespace std;
int main()
{
  int a = 10;
  int& ra = a;
  ra = 20;
  int* pa = &a;
  *pa = 20;
  return 0;
}

通过上述例子,我们调试查看反汇编,发现引用和指针操作底层逻辑是一样的;

(3)引用和指针的不同:

  • 引用概念上定义一个变量的别名,指针存储一个变量地址;
  • 引用在定义时必须初始化,指针没有要求;
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体;
  • 没有NULL引用,但有NULL指针;
  • 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节);
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小;
  • 有多级指针,但是没有多级引用;
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理;
  • 引用比指针使用起来相对更安全;

4.结语

以上就是C++中缺省参数、函数重载以及引用的所有内容啦 ~,缺省参数函数重载以及引用的出现是为了补充C语言语法的不足以及对C语言设计不合理的地方进行优化,引用的出现大大降低了我们学习C语言时相对于指针的难度,也便于我们更好的理解和使用,完结撒花 ~🥳🥳🎉🎉🎉


相关文章
|
11天前
|
存储 安全 编译器
c++入门
c++作为面向对象的语言与c的简单区别:c语言作为面向过程的语言还是跟c++有很大的区别的,比如说一个简单的五子棋的实现对于c语言面向过程的设计思路是首先分析解决这个问题的步骤:(1)开始游戏(2)黑子先走(3)绘制画面(4)判断输赢(5)轮到白子(6)绘制画面(7)判断输赢(8)返回步骤(2) (9)输出最后结果。但对于c++就不一样了,在下五子棋的例子中,用面向对象的方法来解决的话,首先将整个五子棋游戏分为三个对象:(1)黑白双方,这两方的行为是一样的。(2)棋盘系统,负责绘制画面。
|
3月前
|
存储 分布式计算 编译器
C++入门基础2
本内容主要讲解C++中的引用、inline函数和nullptr。引用是变量的别名,与原变量共享内存,定义时需初始化且不可更改指向对象,适用于传参和返回值以提高效率;const引用可增强代码灵活性。Inline函数通过展开提高效率,但是否展开由编译器决定,不建议分离声明与定义。Nullptr用于指针赋空,取代C语言中的NULL。最后鼓励持续学习,精进技能,提升竞争力。
|
4月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
8月前
|
程序员 C++
C++中的函数重载有什么作用
【10月更文挑战第19天】C++中的函数重载有什么作用
115 3
|
8月前
|
编译器 程序员 C++
C++中的函数重载是什么
【10月更文挑战第19天】C++中的函数重载是什么
154 0
|
4月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
11天前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
|
11天前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
|
2月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
84 12

热门文章

最新文章