查看原文
其他

【连载】重温C++之“重载”(第三篇)

bug菌 最后一个bug 2021-01-31

1、简单聊一聊

    今天为大家推荐一首陈同学版本的《离人》,这首歌曲也是很早之前朋友向我推荐的,目前也是在作者的音乐收藏夹中,经常随机播放到,大家有时间可以听一下!

    今天为大家带来重温C++的第三篇文章,作者本次计划连载大概5篇文章吧,虽然目前还有一些小伙伴没有阅读该连载文章,不过后续作者讲解到C++方面一些有趣应用的时候可以回头看看这次连载文章,对于正在学习C++的小伙伴就需要更加好好练习了。好了,下面进入今天的正题!

2、函数带默认参数

    函数带默认值算是C++里面一个比较容易理解的知识,C语言中函数没有这种使用方法,这里主要是为了后面的函数重载进行铺垫,所以这里作者简单温习一下用法和注意事项,函数带默认参数主要是说函数在定义或者声明的时候可以为函数形参指定默认的参数,后续使用可以不用传入相对应的参数使用缺省值即可,参考如下代码:

1#include <iostream>
2using namespace std;
3/******************************************
4 * Fuction: Printf1 
5 * Author : (公众号:最后一个bug)
6 *****************************************/

7int Printf1(int a = 1 ,int b = 2)
8{
9    cout<<"Printf1 : a = "<<a<<";b = "<<b<<endl;    
10}
11
12int Printf2(int a = 1 ,int b = 2); 
13int Printf3(int a ,int b = 2); 
14/******************************************
15 * Fuction: 测试函数默认值 
16 * Author : (公众号:最后一个bug)
17 *****************************************/

18int main(int argc, char** argv) {
19
20    cout<<"Test:函数默认值 "<<endl;  
21    cout<<"----------------- "<<endl;   
22    //Printf1
23    Printf1();
24    Printf1(4);
25    Printf1(4,5);
26    //Printf2
27    cout<<"----------------- "<<endl;   
28    Printf2();
29    Printf2(4);
30    Printf2(4,5);
31    //Printf3
32    cout<<"----------------- "<<endl;   
33    //Printf3(); 需要传递第一个参数 
34    Printf3(4);
35    Printf3(4,5);
36    cout<<"--公众号:最后一个bug--"<<endl;  
37    return 0;
38}
39
40/******************************************
41 * Fuction: Printf2 
42 * Author : (公众号:最后一个bug)
43 *****************************************/

44int Printf2(int a,int b)
45{
46    cout<<"Printf2 : a = "<<a<<";b = "<<b<<endl;    
47}
48/******************************************
49 * Fuction: Printf3
50 * Author : (公众号:最后一个bug)
51 *****************************************/

52int Printf3(int a,int b)
53{
54    cout<<"Printf3 : a = "<<a<<";b = "<<b<<endl;    
55}

    其输出结果如下:

    解析一下:作者定义了三种函数带默认参数的形式,Printf1是直接在定义确定参数缺省值;Printf2是在函数声明处提供缺省值;Printf3只提供部分参数缺省值,具体使用情况参考上面的代码。

    注意事项:

    1)函数参数自左向右从第一提供缺省值的参数开始往右的参数都需要提供缺省参数;

    2)虽然缺省参数能够放在定义或者声明,尽量放在声明,如果放在定义处,定义之前均无法提供缺省参数,会存在编译不通过的情况。

      3)由于提供了缺省值,对于程序的编码也会变得更加简洁,不过注意其实际调用函数所传入的实参都是从左向右,且不会跳跃。


3、函数重载

    重载简单一点说就是同一句话在不同的语境中表达着不同的意思,比如说在C语言中一般都不允许有同名的全局函数出现,而在C++中可以根据函数的参数不同而存在相同名字的函数,这就是函数重载。下面作者简单的写个小代码,供大家参考:

1#include <iostream>
2using namespace std;
3
4int Fuction(int a,int b);
5int Fuction(int a,int b,int c);
6float Fuction(float a,float b);
7/******************************************
8 * Fuction: 测试函数重载 
9 * Author : (公众号:最后一个bug)
10 *****************************************/

11int main(int argc, char** argv) {
12
13    cout<<"Test:函数重载"<<endl;    
14    cout<<"result1:  "<<Fuction(1,1)<<endl;
15    cout<<"result2:  "<<Fuction(1,1,1)<<endl;
16    cout<<"result3:  "<<Fuction((float)2.0,(float)5.0)<<endl;
17    cout<<"--公众号:最后一个bug--"<<endl;  
18    return 0;
19}
20int Fuction(int a,int b)
21{
22    return (a + b); 
23
24int Fuction(int a,int b,int c)
25{
26    return (a + b + c); 
27
28float Fuction(float a,float b)
29{
30    return (a * b); 
31}

    输出结果如下:

    解析一下:通过上面的程序我们大体可以知道,我们通过函数参数的差异调用相同的函数名会最终调用不同的函数实现。这种方式就非常符合我们现实的生活,比如用录音机播放音乐,通过放置不同的磁带就可以播放不同的音乐了,所以说C++语言的特性更加符合人类的思维。

    注意事项:

    1)函数重载时函数名称必须相同,其形参存在差异,比如:参数的类型,参数的个数,参数的顺序。

      2)单独的函数返回值不同不能作为重载的依据。

      3)其实函数重载仅仅只是名称相同,他们本质属于不同的函数,在编译阶段编译器能够通过函数的参数不同来进行编译处理,同时也增加代码了代码的可读性,如果无法通过名字的参数进行区分或者存在二义性,那么会导致编译错误 : 比如我们前面函数默认值的处理,如果一个函数的参数与另外一个函数的前面参数完全一直,而另一个函数其余参数都含有默认值,这样就存在二义性,编译无法通过。

    

4、运算符重载

    重载一般分为函数重载运算符重载,在我们C语言中,对于结构体这样的打包变量是不支持运算符直接进行运算的,一般对于结构体的运算我们大多采用函数的形式进行处理,然后返回最后的结构体。

    如果我们用更加统一的眼光看待的C的话,认为它仅仅只能支持基本数据类型的运算符重载。而C++语言可以重新定义这种的运算符(如“+”等)来满足我们的需求,下面作者给一个简单的小程序供大家参考:

1#include <iostream>
2using namespace std;
3
4class Test
5
{
6private:
7    int a;
8    int b;
9
10public:
11    Test(int param1,int param2);
12    void Printf(void); 
13    friend Test operator+(Test A,Test B); //必须定义为友元 
14};
15/************************************
16 * Fuction :析构函数 
17 * Author  :(公众号:最后一个bug) 
18 ************************************/

19Test::Test(int param1,int param2)
20{
21    a = param1;
22    b = param2;
23}
24/************************************
25 * Fuction :Printf 
26 * Author  :(公众号:最后一个bug) 
27 ************************************/

28void Test::Printf(void)
29{
30    cout<<"a = "<<a<<",b = "<<b<<endl; 
31
32}
33/************************************
34 * Fuction :重载加法运算符 
35 * Author  :(公众号:最后一个bug) 
36 ************************************/

37Test operator+(Test A,Test B)
38{
39    Test Ret(0,0); 
40
41    Ret.a = A.a + B.a;
42    Ret.b = A.b + B.b;
43
44    return Ret;
45}
46
47int main(int argc, char** argv) {
48    Test stTest1(1,2);
49    Test stTest2(1,2);
50    Test stTest3(0,0);
51
52    stTest3 = stTest1 + stTest2; //直接可以进行加法运算 
53    stTest3.Printf();
54    cout<<"公众号:最后一个bug"<<endl; 
55    return 0;
56}

    最后的输出结果我就不贴图了a = 2,b = 4;

    解析一下 :

    1)其实运算符重载你可以简单的认为就是把运算符操作用operator关键字定义的对应函数来进行调用处理即可。其实和我们平时在C语言定义函数来进行结构体加法运算是一样的道理。

    2)在13行我们使用了friend关键字来进行修饰,为了让operator定义的函数内部能够访问Test类的内部私有成员,强调一点的是operator定义的函数不属于类Test,如果operator函数内部访问其Test的私有成员属于外部访问,这样是不允许的,所以我们使用了friend来为其开放访问权限;如果我们不想直接访问类Test内的私有成员,我们可以在public里面为其开放对应接口,然后在operator函数中进行调用即可。

    3)谈到第二点可能很多小伙伴会问为什么不把重载函数放到类里面来实现,这样不就可以访问其类的私有变量了吗?就可以省略friend关键字了!确实,大家可以编码进行实现,这样有一点我们得修改类,如果采用我们现在的全局方式通过调用类的public接口会更加灵活一点。

    4)这样看来我们如果还有其他的类要实现+法运算,同样需要用operator来进行定义,同一个+法运算就有多种用法了,所以叫运算符重载!


5、最后小结

    对于运算符的重载,作者仅仅举例了+法运算,还有"=,++,&&"等等,哪些运算符可以重载,怎么重载,还有一些注意事项,可能需要大家查找相关书籍或者文档进行学习,基本上大同小异,都是一些语法问题,大家依葫芦画瓢+死记硬背基本上可以搞定,其实在真正开发的过程中,一些冷门的语法是用得很少的,甚至基本上不会用,而我们学习主要是为了对这些语法不要太陌生,以后阅读某某大佬或者项目的代码遇到了可以回忆得起来,然后好好查查资料,印象就特别深刻了!

    好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!

推荐好文  点击蓝色字体即可跳转

【连载】重温C++之面向对象(第一篇)

顿悟,神秘的register关键字(C语言篇) 

【典藏】深度剖析单片机程序的运行(C程序版) 

【重磅】剖析MCU的IAP升级软件设计(设计思路篇)

☞ C语言为什么一般不在.h中定义函数或者变量?(精华)

手把手教你写Modbus-RTU协议(理论篇)

深度剖析"bit序"与"字节序"(追思永念)

听说因为代码没"对齐"程序就奔了?(深度剖析)

【典藏】自制小型GUI界面框架(设计思想篇)

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存