【C->Cpp】由C迈向Cpp(3)


正文开始:

目录

(一)函数重载

(1)函数重载

(2)函数重载实现原理

[(二) 引用](#(二) 引用)

(1)引用

(2)语法

[i ,别名:](#i ,别名:)

ii,传参:

iii,返回值:

iv,修改外部变量:

v,避免空指针:


(一)函数重载

(1)函数重载

C语言不允许出现多个同名函数,而C++支持出现同名函数,这需要通过函数重载实现。

函数重载是指在一个类中,有多个同名的函数,但它们的参数列表不同。在C++中,函数重载可以通过函数名相同但参数列表不同来实现,参数列表不同可以包括参数类型、参数个数或者参数顺序等。当调用函数时,编译器会根据参数的类型或个数来自动选择合适的函数进行调用。

(2)函数重载实现原理

在Linux下,C++函数重载的实现原理是使用了一种叫做"名称修饰"(Name Mangling)的技术。当C++源代码被编译成目标文件时,编译器会对函数的名称进行修饰,以区分不同的重载函数。

名称修饰的过程是由编译器自动完成的,它将根据函数的参数类型、参数个数和参数顺序等信息生成一个唯一的符号名。这样,在目标文件中就能够通过不同的符号名来区分不同的重载函数。

(下面一linux的g++为例)

linux下的g++函数在修饰后变成:{ _Z + 函数名长度 + 函数名 + 类型首字母 }

cpp 复制代码
//实例如下
Add(int,int)       ->   call     _Z3Addii
Add(double,double) ->   call     _Z3Adddd
//只要类型不同,类型顺序不同,类型个数不同,都可以让修饰后函数名不同,
//编译器可以区分不同的函数名,这样就构成了重载

编译同一个文件,对于文件中的同一个函数,用gcc和g++编译出来的函数名称是不同的(符合上面规则):

用gcc编译的函数func1函数:

用g++编译的函数func1函数:


函数重载的作用主要有以下几点:

  1. 提高代码的复用性:通过函数重载,可以在一个类中定义多个功能相似的函数,避免了重复编写代码的问题。
  2. 提高程序的可读性:使用函数重载可以让程序更加直观清晰,减少了函数命名的复杂性。
  3. 增强了函数的灵活性:通过函数重载可以根据不同的参数选择不同的实现方式,从而提供了更多的选择。

需要注意以下几点:

  • 重载函数的返回类型不可以作为重载的条件,只有参数列表不同才能作为重载的条件。
  • 重载函数的参数列表必须不同,参数个数不同或者参数类型不同都可以作为重载的条件。
  • 重载函数可以有不同的访问修饰符,比如一个是私有的,一个是公有的。

需要注意的是,C++规定了可以函数重载,但是具体实现的名称修饰规则是由编译器决定的,不同的编译器可能会有不同的修饰规则。

(二) 引用

(1)引用

引用 不是新定义一个变量,而是给已存在的变量取了一个别名* , 编译器不会为引用变量开辟内存空间,它和它引用的变量共同用一块内存空间。*

(2)语法

i ,别名:

引用提供了一个变量的别名,可以通过引用来访问已经存在的变量。这使得代码更加清晰和易读,同时也让函数传参更加方便,避免了拷贝大量数据的开销。

基本使用:

cpp 复制代码
int i = 0;
int& j = i;//给i取别名j,j是i的别名

j与i共用同一块内存地址;

对i与对j的运算是等同的,j++后 i = 1 (其实就是i++ 后 i = 1);

(引用类型必须和引用实体是同种类型的)

引用的特性:

引用在定义时必须初始化;

一个变量可以有多个引用;

可以对别名取别名(套娃)对别名取别名,其实就是对原变量取别名,原变量与他的别名的地位是等同的(一个空间的名字可以是 " i "也可以是 " j " );

引用一旦引用一个实体,不能再引用其他实体;

引用需要与创建变量区分:

cpp 复制代码
int i = 0; 
int j = i;//创建一个变量j初始化为0

ii,传参:

引用作为函数参数,可以将参数按引用传递,而不是按值传递。这样可以避免参数的拷贝,提高函数的执行效率,并且可以在函数内部修改参数的值(也就相当于传址),使得函数能够对传入的参数进行修改(同时也更好理解)。

cpp 复制代码
//形参直接用实参的别名接收,便于直接对实参操作
void swap(int& r1,int& r2)
{
    int tem = r1;
    r1 = r2;
    r2 = tem;
}
int main()
{
    int a = 1,b = 2;
    swap(a,b);//不用再传地址,更好理解

    return 0;
}

iii,返回值:

函数可以返回引用类型 ,这样可以避免拷贝对象的开销,同时也方便链式调用和对象的赋值操作。通过返回引用,函数可以返回一个指向已存在的对象的引用,而不需要创建新的对象。

对于n,是局部变量,存储在栈区,出count函数就会被销毁;

编译器会先将n的值存储在寄存器中,当count函数栈帧销毁后,将寄存器的值赋给ret;

cpp 复制代码
int count()
{
    int n = 0;
    n++;
    return n;
}

int main()
{

    int ret = count();
    
    return 0;
}

对于变量n,是静态变量,存储在静态区,不会随着count函数的销毁而销毁;

编译器仍然会先将n的值存储在寄存器中,当count函数栈帧销毁后,将寄存器的值赋给ret;

cpp 复制代码
int count()
{
    static int n = 0;
    n++;
    return n;
}

int main()
{

    int ret = count();
    
    return 0;
}

为什么两种都需要寄存器的帮助?

如果是返回引用,还需要寄存器的帮助吗?

cpp 复制代码
​
int& count1()
{
    int n = 0;
    n++;
    return n;
}

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

int main()
{

    int ret1 = count1();
    int ret2 = count2();
    return 0;
}

​

显然不需要,这样就减少了拷贝;
引用作返回值,同时也可以做可修改的左值,因为引用本质上就是变量的别名,变量当然可修改;

cpp 复制代码
#define N 50

//静态顺序表
struct AY
{
    int a[N];
    int size;    //大小
    int capacity;//容量
}

//检查是否越界
int& posAt(AY& ay,int i)
{
    assert(i < N)
    return ay.a[i];
}

int main()
{
    AY ay;
    for(int i = 0;i < N;i++)
    {
        posAt(ay,i) = i * 10;//返回引用可作为可被修改的左值
    }
}

iv,修改外部变量:

引用可以作为函数的返回值,在函数内部对外部的变量进行修改。这种方式可以用于实现一些特殊的操作,如对象的赋值操作符重载等。通过引用,可以直接修改外部的变量,而不需要通过指针等方式。

v,避免空指针:

引用在定义时必须初始化,并且不能被修改指向其他对象,这样可以避免了指针的空引用问题。使用引用可以更加安全地操作对象,避免了空指针异常的发生。


完~

未经作者同意禁止转载

相关推荐
鸿芯微控科技2 分钟前
MFC质量流量控制器流量不准怎么排查?设定值、反馈值与参考流量对比,附Python代码
c++·python·mfc
大尚来也7 分钟前
用 Python 自动整理文件、重命名、分类电脑文件夹
开发语言·python
CVer儿9 分钟前
c++二级指针
开发语言·c++
mlidongfeng1 小时前
[AI][C++26] SIMD 编程模型思考
开发语言·c++·人工智能
梓䈑1 小时前
【用 Vibe Coding 实现的 C++17 在线判题系统】OpenCode 入门指南:从环境搭建到上下文管理
c++·ai编程
j7~1 小时前
【Linux】二十七.线程篇四《Linux多线程编程:线程互斥(互斥量的底层到封装)、线程安全和冲入、死锁》---详解
linux·开发语言·c++·线程安全·死锁·线程互斥·重入
啦啦啦啦啦zzzz1 小时前
贪心算法和动态规划
c++·算法·贪心算法·动态规划
刘名喜1 小时前
第09篇-协程基础-Kotlin异步编程
开发语言·kotlin·springboot
其实防守也摸鱼1 小时前
HackBar 工具完全指南:信息探测、漏洞验证与安全测试实战
开发语言·人工智能·学习·安全·网络安全·安全威胁分析·安全性测试
我不是懒洋洋1 小时前
从零实现一个分布式数据集成:Airbyte的核心设计
c++