<C++>核心编程之引用与函数提高,剖析引用的本质和函数重载方法

简介: <C++>核心编程之引用与函数提高,剖析引用的本质和函数重载方法

详解引用


引用的基本使用


语法:数据类型  &新变量名 =原来变量名

作用:给变量起别名


注意事项:


1、引用必须初始化

2、一旦初始化就不能更改(具体原因在下面引用本质上会讲到


示例:


int a = 10; int c = 20;


如果写 int &b;这是错误的,没有初始化引用,编译器不知道b指向的地址。

所以这样写 int &b=a;那么现在ba 的别名,他们的地址相同,存放的数据也都一样。这时如果写 b=c;我们不会认为 bc的别名,只会认为是把c的值赋给了b,当然也赋给了a


引用做函数参数


   这是引用最为方便和精辟的地方了,直接代替指针来进行引用传递,我们举个最为经典的例 子:swap交换函数.


void swap(int &x,int &y)
{
        int t = a;
        a = b;
        b = t;
        cout << "swap03 a =" << a << endl;
        cout << "swap03 b =" << b << endl;
}
int main()
{
    int a = 10, b = 20;
        /*值传递形参不能修饰实参
        地址传递可以修饰实参*/
        swap(a, b);//引用做函数参数也可以修饰实参
}

   这里主函数传的实参是a,b形参是int &x,int &y;不就是int &x = a, int &y = b 吗,xa地址相同,yb地址相同,xy的变化必会导致a,b的变化,因此属于地址传递,不会令编译器产生副本,节省空间的同时,代码也更简洁。


引用做函数返回值


   我们知道函数语法第一个就要写函数返回值类型,在数据类型后加上&符号,就可以返回该函数的引用,有的也叫返回函数的地址,其实意思都一样,只是叫法不同罢了。


注意事项:


1、不要返回局部变量的引用

2、返回函数的引用可以作为左值


 示例:


#include<iostream>
using namespace std;
int& func1()
{
        int a = 10;//局部变量放在四区中的栈区,返回后会被编译器自动销毁
        return a;
}
int& func2()
{
        static int a = 10;
        return a;
}
int main()
{
        int& ref1 = func1();
        int& ref2 = func2();
        cout << "a =" << ref1 << endl;
        cout << "a =" << ref1 << endl;//乱码
        cout << "a =" << ref2 << endl;
        func2() = 1000;//如果函数的返回值是引用,那这个函数调用可以作为左值
        cout << "a =" << ref2 << endl;
}

   func1函数开辟在栈区,返回的引用会被编译器自动释放掉,main函数中我用&ref1作为func1的引用返回,并输出ref1的值,不出意外,第二次输出的时候会出现乱码,其实就是ref的新地址,func1返回的地址已经被释放掉,第一次能输出是因为编译器做出了保留。func2虽然也是开辟在栈区,但是a 的地址却是放在了全局区,由操作系统自动释放,所以返回func2的引用不会被编译器释放,而且可以作为左值变化数据,最后一个cout结构必当是1000,附上结果图。


image.png


常量引用


这个就好理解了,就是传参的时候加上const关键字,防止误操作

示例:


//打印数据函数
void showData(const int& a)
{
    //a=100; 这里不能做出修改,防止误操作
    cout << "a=" <<a<< endl;
}


引用的本质


引用的本质是一个指针常量

编译器发现是引用自动将int &ref=a;转变为 int *const ref=&a;并且再给 ref赋值时,自动解引用 ref=100 改为 *ref = 100


示例:


void fun1(int &ref)  //自动转变为 int *const ref=&a
{
    ref = 100; //转换成*ref=100
}
 C++推荐使用引用,因为引用的本质是指针常量,但是有关指针的操作编译器都帮我们做了


函数提高


学习C很快就会接触函数了,这里主要讲你少见的函数形式来做一个函数提高


函数默认值


语法:返回类型值 函数名 (形参=默认值){}

注意事项


1
、如果某个位置已经有默认参数,那么从这个位置开始从左往右都要有默认值
2
、声明和实现只能有一个有默认参数,如果声明的时候给了形参默认值,那么下面对函数的实现就不能再给该形参默认值


示例:


int fun1(int a, int b, int c=50);
int fun1(int a, int b, int c)
{
        return a + b + c;
}
int main()
{
        cout << fun1(10,30) << endl;
}

这里cout的结果我们都能猜到是90;如果我们修改代码给形参b默认值,而不给c默认值,就会违反第一个注意事项,这时给c也默认值就解决问题了。


函数占位参数


语法:返回值类型 函数名(数据类型){}

占位参数可以有默认参数:


void fun2(int a,int=20) 
{
    cout << a<<"is this is fun2" << endl;
}


调用:


fun2(10);


结果:

fun2(10);


函数重载及注意事项


函数重载需要函数都在一个作用域下
函数名相同,提高复用性
函数参数类型不同 或者 个数不同 顺序不同


#include<iostream>
using namespace std;
void func()
{
        cout << "func 的调用" << endl;
}
void func(int a)
{
        cout << "func(int a)的调用" << endl;
}
void func(double a)
{
        cout << "func(double a)的调用" << endl;
}
void func(int a, double b)
{
        cout << "func(int a,double b)的调用" << endl;
}
void func(double b,int a)
{
        cout << "func(doubel b,int a)的调用" << endl;
}
//函数返回值不可以做重载条件
int main()
{
        func();
        func(10);
        func(12.3);
        func(10,20.1);
        func(30.1,20);
}

这里写五个func函数,四个重载,并配上提示助理解,输出结果如下:


image.png


函数重载注意事项:


1、引用可作为重载的条件


void funct(int& a)
{
        cout << "funct(int &a)的调用" << endl;
}
void funct(const int& a)
{
        cout << "funct(const int &a)的调用" << endl;
}

调用方法:int a = 10;  funct(a);   funct(20); 重载时加上const 关键字就相当于是一个常量,调用的时候直接写入数据即可。


2、函数重载碰到默认参数


void func2(int a,int b=10)
{
        cout << "func(int a,int b)的调用" << endl;
}
void func2(int a)
{
        cout << "func(double a)的调用" << endl;
}

这里调用func2方法必然会报错,因为两个函数发生了重载,而且调用方法一致,都是

func2(数值);那么就会产生二义性,编译器无法识别调用的是哪个重载的方法。

相关文章
|
10天前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
118 60
|
1天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
5天前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
|
13天前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
36 6
|
13天前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
16 0
C++ 多线程之线程管理函数
|
17天前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
71 1
|
17天前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
29 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
5天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
15 4
|
5天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
15 4
|
5天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
10 1