草庐IT

重载的奥义之函数重载

明解嵌入式 2023-03-28 原文

一、基本定义        

        重载,顾名思义从字面上理解就是重复装载,打一个不恰当的比方,你可以用一个篮子装蔬菜,也可以装水果或者其它,使用的是同一个篮子,但是可以用篮子重复装载的东西不一样。

        函数重载是C++多态(静态多态)的特征体现,它可以允许重复使用同一个函数名(篮子)的函数,但是函数的参数列表(篮子装的东西)是可以不一样的。这样就可以利用函数的重载功能设计一系列功能相近,但是功能细节不一样的函数接口。


二、应用举例        

        以同一个函数printData为例:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void printData(const char *str, int num)
 5 {
 6   //函数体;
 7 }
 8 
 9 void printData(const char *str)
10 {
11   //函数体;
12 }
13 
14 void printData(double data, int num)
15 {
16   //函数体;
17 }
18 
19 void printData(int data, int num)
20 {
21   //函数体;
22 }
23 
24 void printData(long data, char num)
25 {
26   //函数体;
27 }
28 
29 class Test
30 {
31   public:
32          void MyPrint(int num) {cout << "class int: " << num << endl;}
33          void MyPrint(float num) {cout << "class float: " << num << endl;}
34          void MyPrint(char num) {cout << "class char: " << num << endl;}
35 };
36 
37 int main(void)
38 {
39   printData("hello", 5); // (const char *str, int num)
40   printData("hello"); // (const char *str)
41   printData(1993.0, 97);
42   printData(1993, 98);
43   printData(1993L, 99);
44   Test test1;
45   test1.MyPrint(2); // class int: 2
46   test1.MyPrint(2.0f); // class float: 2.0 浮点型必须要显式类型,否则编译器不知道该转换为int还是float。
47   test1.MyPrint("hello"); // class char: hello
48   return 0;
49 }

  使用重载函数时,需要在函数调用中使用与对应的重载函数匹配的函数参数类型。

        而如下:

1 unsigned int para = 4321;
2 printData(4321, 5);

        此时的printData调用和哪个原型匹配呢?答案它不与任何函数原型匹配,而没有匹配的原型不会停止调用其中某一个函数,C++会尝试用标准的强制类型转换与之匹配,比如使用 printData(double data, int num),就可以将para的类型强制转换为double类型。但是还有printData(int data, int num)和printData(long data, char num)这两个函数可以强制转换para。因此,C++将拒绝这种函数的调用,将这种调用视为错误。

        重载函数通常用在同一个作用域内,用同一个函数名命名一组功能相似的函数,这样做减少了函数名的数量,提高了函数的通用性,避免了名字空间的污染,对于程序的可读性有很大的好处。


三、非函数重载的情况

        下面这种两种情况不能视为函数重载:

1 int fun(int a);
2 int fun(int &a);

        从编译器的角度出发,参数a与参数列表原型int a和int &a都匹配,编译器无法确定使用哪个函数,为避免这种混乱,编译器在检查参数类型时将把类型本身和类型引用看作是同一个特征类型。

1 int fun(int a, float b);
2 double fun(int a, float b);

        C++不允许这样的方式重载函数,虽然返回值可以不一样,但是参数列表必须不一样。


四、函数重载的使用原则

        (1)、仅当函数的基本功能比较相近,但是需要使用不同形式的参数实现功能时才应该使用函数重载,尽量不要用同一函数名去实现完全不相干的功能;

        (2)、在同一个作用范围内使用函数重载,同一个范围即:同一个命名空间或者同一个类等;

        (3)、重载函数的名称必须相同,函数的参数列表须不相同,即参数列表中参数的类型,参数的个数或参数的顺序不相同;

        (4)、重载函数可以有相同的返回值类型或者不同的返回值类型,反之仅仅是返回类型不同不足以作为函数的重载。


五、FAQ

1、C++中对函数重载是如何处理的?

        在.cpp文件中,虽然两个函数的函数名一样,但是,C++编译器在内部使用“名称修饰”或“名称矫正”转换,它根据函数中参数列表的区别为每个函数进行加密 ,例如:

        int fun(int a, float b)和double fun(int a, float b)

        编译器在内部可以转换为:

        ?fun@@YAHHH@Z和?fun@@YAMMM@Z

         "?"表示名称开始,"?"后边是函数名;“@@YA”表示参数表开始,后边的3个字符分别表示返回值类型,两个参数类型;“@Z”表示名称结束。

        由于在.cpp文件中,两个函数生成的符号表中字符的名称不一样,所以是可以编译通过的。

2、C语言中为什么不能支持函数重载?

        编译器在编译.c文件时,只会给函数进行简单的重命名。具体的方法是给函数名之前加上"_”;所以编译前两个函数名相同的函数在编译之后的函数名也照样相同;因此调用时会因为不知道到底调用哪个而出错。

        int fun(int a, float b)和double fun(int a, float b)

        编译器在内部都转换为:_fun,无法区分,

        只有不同的函数名字int fun1(int a, float b)和double fun2(int a, float b)

        编译器在内部转换为:_fun1和_fun2,这才能区分开来。


 更多技术内容和书籍资料获取敬请关注微信公众号“明解嵌入式”

有关重载的奥义之函数重载的更多相关文章

  1. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  2. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  3. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  4. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  5. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  6. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  7. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  8. ruby - 是否可以从也在该模块中的类内部调用模块函数 - 2

    在这段Ruby代码中:ModuleMClassC当我尝试运行时出现“'M:Module'的未定义方法'helper'”错误c=M::C.new("world")c.work但直接从另一个类调用M::helper("world")工作正常。类不能调用在定义它们的同一模块中定义的模块函数吗?除了将类移出模块外,还有其他解决方法吗? 最佳答案 为了调用M::helper,你需要将它定义为defself.helper;结束为了进行比较,请查看以下修改后的代码段中的helper和helper2moduleMclassC

  9. ruby - 将运算符传递给函数? - 2

    也许这听起来很荒谬,但我想知道这对Ruby是否可行?基本上我有一个功能...defadda,bc=a+breturncend我希望能够将“+”或其他运算符(例如“-”)传递给函数,这样它就类似于...defsuma,b,operatorc=aoperatorbreturncend这可能吗? 最佳答案 两种可能性:以方法/算子名作为符号:defsuma,b,operatora.send(operator,b)endsum42,23,:+或者更通用的解决方案:采取一个block:defsuma,byielda,bendsum42,23,

  10. ruby - 我可以在 Ruby 1.9.x 中使用无参数函数吗? - 2

    所以我正在研究RubyKoans,而且我遇到了一个我认为是ruby1.9.x特有的问题。deftest_calling_global_methods_without_parenthesesresult=my_global_method2,3assert_equal5,resultend我明白了:james@tristan:~/code/ruby_projects/ruby_koans$rake(in/home/james/code/ruby_projects/ruby_koans)cdkoans/home/james/.rvm/rubies/ruby-1.9.2-p180/bin/ru

随机推荐