函数重载 订阅
重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。不能只有函数返回值类型不同。 展开全文
重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。不能只有函数返回值类型不同。
信息
外文名
overloaded function
程序类型
C++
中文名
重载函数
属    性
特殊函数
重载函数说明
两个重载函数必须在下列一个或两个方面有所区别:1、函数的参数个数不同。2、函数的参数类型不同或者参数类型顺序不同,C++的这种编程机制给编程者极大的方便,不需要为功能相似、参数不同的函数选用不同的函数名,也增强了程序的可读性。C++运算符重载的相关规定如下:(1)不能改变运算符的优先级;(2)不能改变运算符的结合型;(3)默认参数不能和重载的运算符一起使用;(4)不能改变运算符的操作数的个数;(5)不能创建新的运算符,只有已有运算符可以被重载;(6)运算符作用于C++内部提供的数据类型时,原来含义保持不变。
收起全文
精华内容
下载资源
问答
  • C++函数重载详解
    千次阅读
    2021-08-03 22:28:03

    在实际开发中,有时候我们需要实现几个功能类似的函数,只是有些细节不同。例如希望交换两个变量的值,这两个变量有多种类型,可以是 int、float、char、bool 等,我们需要通过参数把变量的地址传入函数内部。在C语言中,程序员往往需要分别设计出三个不同名的函数,其函数原型与下面类似:

    void swap1(int *a, int *b);      //交换 int 变量的值
    void swap2(float *a, float *b);  //交换 float 变量的值
    void swap3(char *a, char *b);    //交换 char 变量的值
    void swap4(bool *a, bool *b);    //交换 bool 变量的值
    

    但在C++中,这完全没有必要。C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading)。借助重载,一个函数名可以有多种用途。

    参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。

    【示例】借助函数重载交换不同类型的变量的值:

    #include <iostream>
    using namespace std;
    //交换 int 变量的值
    void Swap(int *a, int *b){
        int temp = *a;
        *a = *b;
        *b = temp;
    }
    //交换 float 变量的值
    void Swap(float *a, float *b){
        float temp = *a;
        *a = *b;
        *b = temp;
    }
    //交换 char 变量的值
    void Swap(char *a, char *b){
        char temp = *a;
        *a = *b;
        *b = temp;
    }
    //交换 bool 变量的值
    void Swap(bool *a, bool *b){
        char temp = *a;
        *a = *b;
        *b = temp;
    }
    int main(){
        //交换 int 变量的值
        int n1 = 100, n2 = 200;
        Swap(&n1, &n2);
        cout<<n1<<", "<<n2<<endl;
       
        //交换 float 变量的值
        float f1 = 12.5, f2 = 56.93;
        Swap(&f1, &f2);
        cout<<f1<<", "<<f2<<endl;
       
        //交换 char 变量的值
        char c1 = 'A', c2 = 'B';
        Swap(&c1, &c2);
        cout<<c1<<", "<<c2<<endl;
       
        //交换 bool 变量的值
        bool b1 = false, b2 = true;
        Swap(&b1, &b2);
        cout<<b1<<", "<<b2<<endl;
        return 0;
    }
    

    运行结果:
    200, 100
    56.93, 12.5
    B, A
    1, 0

    本例之所以使用Swap这个函数名,而不是使用swap,是因为 C++ 标准库已经提供了交换两个变量的值的函数,它的名字就是swap,位于algorithm头文件中,为了避免和标准库中的swap冲突,本例特地将S大写。

    既然标准库已经提供了 swap() 函数,本例为何又要自己实现一遍呢,这不是费力不讨好吗?交换两个变量的值是一个经典且实用的函数重载案例,本例这样做仅仅是为了教学演示,并不是要替代标准库中的 swap(),读者在以后的编码过程中也应该坚持使用标准库中的 swap()。

    通过本例可以发现,重载就是在一个作用范围内(同一个类、同一个命名空间等)有多个名称相同但参数不同的函数。重载的结果是让一个函数名拥有了多种用途,使得命名更加方便(在中大型项目中,给变量、函数、类起名字是一件让人苦恼的问题),调用更加灵活。

    在使用重载函数时,同名函数的功能应当相同或相近,不要用同一函数名去实现完全不相干的功能,虽然程序也能运行,但可读性不好,使人觉得莫名其妙。

    注意,参数列表不同包括参数的个数不同、类型不同或顺序不同,仅仅参数名称不同是不可以的。函数返回值也不能作为重载的依据。

    函数的重载的规则:

    • 函数名称必须相同。
    • 参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)。
    • 函数的返回类型可以相同也可以不相同。
    • 仅仅返回类型不同不足以成为函数的重载。

    C++ 是如何做到函数重载的

    C++代码在编译时会根据参数列表对函数进行重命名,例如void Swap(int a, int b)会被重命名为_Swap_int_intvoid Swap(float x, float y)会被重命名为_Swap_float_float。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错,这叫做重载决议(Overload Resolution)。

    不同的编译器有不同的重命名方式,这里仅仅举例说明,实际情况可能并非如此。

    从这个角度讲,函数重载仅仅是语法层面的,本质上它们还是不同的函数,占用不同的内存,入口地址也不一样。

    C++函数重载过程中的二义性和类型转换

    上节我们讲到,发生函数调用时编译器会根据传入的实参的个数、类型、顺序等信息去匹配要调用的函数,这在大部分情况下都能够精确匹配。但当实参的类型和形参的类型不一致时情况就会变得稍微复杂,例如函数形参的类型是int,调用函数时却将short类型的数据交给了它,编译器就需要先将short类型转换为int类型才能匹配成功。

    现在有以下几种形式的函数重载(例1):

    #include <iostream>
    using namespace std;
    //1号函数
    void func(char ch){
        cout<<"#1"<<endl;
    }
    //2号函数
    void func(int n){
        cout<<"#2"<<endl;
    }
    //3号函数
    void func(long m){
        cout<<"#3"<<endl;
    }
    //4号函数
    void func(double f){
        cout<<"#4"<<endl;
    }
    int main(){
        short s = 99;
        float f = 84.6;
       
        func('a');  //不需要类型转换,调用func(char)
        func(s);  //将short转换成int,调用func(int)
        func(49);  //不需要类型转换,调用func(int)
        func(f);  //将float转换成double,调用func(double)
        return 0;
    }
    

    运行结果:

    #1
    #2
    #2
    #4

    这段代码很容易理解,相信大家都不会有什么疑问。对代码稍作修改,将2号函数void func(int n)去掉(例2):

    #include <iostream>
    using namespace std;
    //1号函数
    void func(char ch){
        cout<<"#1"<<endl;
    }
    //3号函数
    void func(long m){
        cout<<"#3"<<endl;
    }
    //4号函数
    void func(double f){
        cout<<"#4"<<endl;
    }
    int main(){
        short s = 99;
        float f = 84.6;
      
        func('a');
        func(s);
        func(49);
        func(f);
        return 0;
    }
    

    这段代码在编译时发生了错误,大概的意思是:func(s)func(49)这两个函数发生调用错误,它们可以匹配三个重载函数中的任何一个,编译器不知道如何抉择。

    这着实有点让人摸不着头脑!根据以往的编程经验,s 和 49 不都应该被转换成 long 类型,从而匹配3号函数void func(long m)吗?这种推论在一般的函数调用或者四则运算中确实没错,但它不一定适用于重载函数!

    C++ 标准规定,在进行重载决议时编译器应该按照下面的优先级顺序来处理实参的类型:

    优先级包含的内容举例说明
    精确匹配不做类型转换,直接匹配(暂无说明)
    只是做微不足道的转换从数组名到数组指针、从函数名到指向函数的指针、从非 const 类型到 const 类型。
    类型提升后匹配整型提升从 bool、char、short 提升为 int,或者从 char16_t、char32_t、wchar_t 提升为 int、long、long long。
    小数提升从 float 提升为 double。
    使用自动类型转换后匹配整型转换从 char 到 long、short 到 long、int 到 short、long 到 char。
    小数转换从 double 到 float。
    整数和小数转换从 int 到 double、short 到 float、float 到 int、double 到 long。
    指针转换从 int * 到 void *。

    C++ 标准还规定,编译器应该按照从高到低的顺序来搜索重载函数,首先是精确匹配,然后是类型提升,最后才是类型转换;一旦在某个优先级中找到唯一的一个重载函数就匹配成功,不再继续往下搜索。

    如果在一个优先级中找到多个(两个以及以上)合适的重载函数,编译器就会陷入两难境地,不知道如何抉择,编译器会将这种模棱两可的函数调用视为一种错误,因为这些合适的重载函数同等“优秀”,没有一个脱颖而出,调用谁都一样。这就是函数重载过程中的二义性错误。

    在例1中,func('a')func(49)分别和void func(char)void func(int)精确匹配;func(s)没有精确匹配的重载函数,编译器将 s 的类型提升为 int 后和void func(int)匹配成功;func(f)也是类似的道理,将 f 提升为 double 类型后和void func(double)匹配成功。

    在例2中,func(s)func(49)没有精确匹配的重载函数,将它们的类型都提升为 int 后仍然不能匹配,接下来进入自动类型转换阶段,发现 s 被转换为 char(整型转换)、long(整型转换)、double(整数和小数转换)后都有比较合适的函数,而且它们在同一个优先级中,谁也不比谁优秀,调用哪个都一样,产生了二义性,所以编译器会报错。

    注意,类型提升和类型转换不是一码事!类型提升是积极的,是为了更加高效地利用计算机硬件,不会导致数据丢失或精度降低;而类型转换是不得已而为之,不能保证数据的正确性,也不能保证应有的精度。类型提升只有上表中列出的几种情况,其他情况都是类型转换。

    多个参数时的二义性

    当重载函数有多个参数时也会产生二义性,而且情况更加复杂。C++ 标准规定,如果有且只有一个函数满足下列条件,则匹配成功:

    • 该函数对每个实参的匹配都不劣于其他函数;
    • 至少有一个实参的匹配优于其他函数。

    假设现在有以下几个函数原型:

    void func(int, int);  //①
    void func(char, int, float);  //②
    void func(char, long, double);  //③
    

    我们来分析如下的调用会发生什么情况:

    short n = 99;
    func('@', n, 99);
    func('@', n, 99.5);
    

    函数原型func(int, int)只有两个参数,而函数调用有三个参数,很容易看出来不匹配,在初次筛选时就会被过滤掉,接下来我们只讨论②③个函数原型。

    1. 先来看第一个函数调用。如果只考虑第一个实参'@',那么②③两个函数都能够精确匹配,谁也不比谁优秀,是平等的;如果只考虑第二个实参n,对于②,需要把 short 提升为 int(类型提升),对于③,需要把 short 转换为 long(类型转换),类型提升的优先级高于类型转换,所以②胜出;如果只考虑第三个实参99,②③都要进行类型转换,没有哪一个能胜出,它们是平等的。

    从整体上看,②③在第一、三个实参的匹配中是平等的,但②在第二个实参的匹配中胜出,也就是说,②对每个实参的匹配都不劣于③,但有一个实参的匹配优于③,所以②最终脱颖而出,成为被调用函数。

    1. 再来看第二个函数调用。只考虑第一个实参时②③是平等的,没有谁胜出;只考虑第二个实参时②胜出;只考虑第三个实参时,②需要类型转换,③能够精确匹配,精确匹配的优先级高于类型转换,所以③胜出。

    从整体上看,②③在第一个实参的匹配中是平等的,②在第二个实参的匹配中胜出,③在第三个实参的匹配中胜出,它们最终“打成了平手”,分不清孰优孰劣,所以编译器不知道如何抉择,会产生二义性错误。

    总结

    在设计重载函数时,参数类型过少或者过多都容易引起二义性错误,因为这些类型相近,彼此之间会相互转换。

    例如我们要设计几个重载函数来处理数值,数值包括小数和整数,如果只提供了以下两个函数原型:

    void func(int);
    void func(double);
    

    那么下面的函数调用就会产生二义性错误:

    long n = 1000;func(n);
    

    n 是 long 类型,转换为 int 或 double 的优先级都是一样的,编译器不知道如何抉择。

    如果添加一个函数原型void func(long);,或者去掉一个函数原型void func(int);,无论再怎么调用也不会出错了。

    更多相关内容
  • C++中函数重载实例详解 函数重载: 1、具有相同的名称,执行基本相同的操作,但是使用不同的参数列表。 2、函数具有多态性。 3、编译器通过调用时参数的个数和类型确定调用重载函数的哪个定义。 4、只有对不同的...
  • 常成员函数和非常成员函数之间的重载 首先先回忆一下常成员函数 声明:<类型标志符>函数名(参数表)const; 说明: (1)const是函数类型的一部分,在实现部分也要带该关键字。 (2)const关键字可以用于对重载...
  •  好了,简单介绍下函数重载,学过编程的都对这个重载很熟悉了。函数重载的判断标识是它的函数参数列表,而不是返回值来判断的。所以像 long gronk(int n, float m); double gronk(int , float m);  是...
  • C语言中没有函数重载 C++语言中有函数重载 函数名相同,参数个数不同、参数类型不同、参数顺序不同 例如下面就是函数重载 void sum(int a, int b){ cout << a+b << endl; } void sum(int a, double ...
  • 详解C++之函数重载

    2020-12-17 04:35:31
    函数重载本质 c++中通过函数名和函数确定一个函数 所以相同的函数名,不同参数也是可以的 不同于c语言,c语言没有函数重载,函数的本质地址就是函数名 函数重载发生在同一个作用域内 类中的重载 构造函数重载 普通...
  • 在面向对象的编程中,很多语言都支持函数重载,能根据函数传递的不同个数、类型的参数来做不同的操作,JS对它却不支持,需要我们额外做些小动作。
  • 在C++中,我们也能够把具有相同功能的函数整合到一个函数上,而不必去写好多个函数名不同的函数,这叫做函数的重载。以下是对C++中的函数重载进行了详细的分析介绍,需要的朋友可以过来参考下
  • C++的函数重载

    2021-02-27 03:23:27
    ——每个现象后面都隐藏一个本质,关键在于我们是否去挖掘写在前面:函数重载的重要性不言而明,但是你知道C++中函数重载是如何实现的呢(虽然本文谈的是C++中函数重载的实现,但我想其它语言也是类似的)?...
  • 1、普通的函数重载是,函数的参数或参数类型必须先有所不同,返回类型也可不同。  2、虚函数重载时,要求函数名,返回类型,参数个数,参数类型,顺序都要与基类函数原型完全相同  a、当返回类型不相同,其他...
  • 函数重载

    2018-07-26 11:45:04
    函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。 重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的...

    定义

    函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。

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

    int Add(int left, int right) 
    {    
        return left+right; 
    }
    
    double Add(double left, double right) 
    {   
        return left+right; 
    }
    
    long Add(long left, long right) 
    {    
        return left+right; 
    }
    
    int main() 
    {    
        Add(10, 20);    
        Add(10.0, 20.0);    
        return 0; 
    }

    函数重载定义要求:

    • 同名函数
    • 同名函数的形参列表(参数个数、类型、顺序)必须不同。
    • 返回值不做要求

    为什么需要函数重载

    • 如果没有函数重载机制,如在c中,要printf函数打印不同类型的数据就需要取不同的名字。printf_int、printf_string...如果有多个,就需要为实现同一个功能的函数取很个名字
    • 类的构造函数跟类名相同,如果没有函数重载机制,要想实例化不同的对象,就会相当麻烦。
    • 操作符重载,本质上就是函数重载,它大大丰富了已有操作符的含义,方便使用。

    编译器如何解决命名冲突

    名字修饰(Name Mangling)

    在c/c++中,一个程序要运行起来,需要经历:预处理、编译、汇编、链接

    名字修饰是一种在编译过程中,将函数、变量的名称重新改编的机制,简单地说就是编译器为了区分各个函数,将函数通过一定算法,重新修饰为一个全局唯一的名称。

    为什么c语言不支持函数重载

    • C语言:只是在函数名字前面添加了下下划线
    int Add(int left, int right);
    
    int main() 
    {    
        Add(1, 2);    
        return 0; 
    }


    上述Add函数只给了声明没有给定义,因此在链接时就会报错。
    提示:在main函数中引用的Add函数找不到函数体。从报错结果中可以看到,C语言只是在函数名前添加了下划线。因此当工程中存在相同函数名的函数,就会产生冲突。

    • C++:映射机制为:返回类型+函数名+参数列表
    int Add(int left, int right); 
    
    int main() 
    {    
        Add(1, 2);   
        return 0; 
    }


    通过上述错误可以看出,编译器实际在底层使用的不是Add名字,而是被重新修饰过的一个比较复杂的名字,被重新修饰后的名字中包含了:函数的名字以及参数类型。这就是为什么函数重载中几个同名函数要求其参数列表不同的原因。只要参数列表不同,编译器在编译时通过对函数名字进行重新修饰,将参数类型包含在终的名字中,就可保证名字在底层的全局唯一性。

       Linux对于函数的名字是如何修饰的---作用域+返回类型+函数名+参数列表
       在g++下这种编码方式是:
       1、所有编码后的符号都由_Z开头
       2、如果有作用域符,则在_Z之后加上N
       3、接下来是命名空间名字长度+N和类命长度+C
       4、如果有作用域符,则以E结尾
       5、后加上函数形参符号,int就是i,float就是f,有几个形参就写几个符号
    

    编译器如何解析重载函数调用

    编译器在对重载函数调用进行处理时,由语法分析、C++文法、符号表、抽象语法树交互处理

    1. 由匹配文法中的函数调用,获取函数名;
    2. 获得函数各参数表达式类型;
    3. 语法分析器查找重载函数,符号表内部经过重载解析返回最佳的函数
    4. 语法分析器创建抽象语法树,将符号表中存储的最佳函数绑定到抽象语法树上

    其中,重载函数解析大致可以分为三步:

    1. 根据函数名确定候选函数集
    2. 从候选函数集中选择可用函数集合
    3. 从可用函数集中确定最佳函数,或由于模凌两可返回错误

    c++中能否将一个函数按照c的风格编译

    有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加 extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。

    extern "C" int Add(int left, int right);
    
    int main() 
    {    
        Add(1,2);    
        return 0; 
    }

    c/c++函数调用约定

    函数调用约定
    常见的函数调用约定[5]:cdecl,stdcall,fastcall,thiscall,naked call
    MFC调用约定(VS6:Project Settings->C/C++ Calling convention:)

    • __cdecl(C调用约定.The C default calling convention)C/C++ 缺省调用方式

      1) 压栈顺序:函数参数从右到左
      2) 参数栈维护:由调用函数把参数弹出栈,传送参数的内存栈由调用函数来维护
      (正因为如此,实现可变参数vararg的函数(如printf)只能使用该调用约定)
      3) 函数修饰名约定:VC将函数编译后会在函数名前面加上下划线前缀
      4) 每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大

    • __stdcall (Pascal方式清理C方式压栈,通常用于Win32 Api中)

      1) 压栈顺序:函数参数从右到左
      2) 参数栈维护:被调用函数把参数弹出栈(在退出时清空堆栈)
      3) 函数修饰名约定:VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上”@”和参数的字节数

    • __fastcall (快速调用约定,通过寄存器来传送参数)

      1) 压栈顺序:用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送
      2) 参数栈维护:被调用函数在返回前清理传送参数的内存栈
      3) 函数修饰名约定:VC将函数编译后会在函数名前面加上”@”前缀,在函数名后加上”@”和参数的字节数

    • thiscall (本身调用,仅用于“C++”成员函数)

      1) 压栈顺序:this指针存放于CX/ECX寄存器中,参数从右到左的压栈顺序
      2) thiscall不是关键词,因此不能被程序员指定

    • naked call (裸调)

      1) 当采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容
      (这些代码称作 prolog and epilog code,一般ebp、esp的保存是必须的)
      2) naked call不产生这样的代码。naked call不是类型修饰符,故必须和_declspec共同使用

    展开全文
  • python中有函数重载

    2020-12-17 13:34:46
    python中没有函数重载 为了考虑为什么python不提供函数重载,首先我们要研究为什么需要提供函数重载函数重载主要是为了解决两个问题: 可变参数类型。 可变参数个数。 另外,一个基本的设计原则是,仅仅当两个...
  • 函数重载的替代方法-伪重载,下面看一个具体的实例代码。 <? php //函数重载的替代方法-伪重载 // //确实,在PHP中没有函数重载这个概念,让很多时候我们无法进行一些处理,甚至有时候不得不在函数后面定义好N...
  • 什么叫重载 名字相同 ,参数类型不同 方法重载 方法重载在类中定义多个同名的方法,但是每一个同名的方法要求不同数据类型和不同参数 下面来实现一个方法重载 以ArrayList 为例 可以查看数据 可以删除数据 删除可以...

    什么叫重载

    名字相同 ,参数类型不同

    方法重载

    方法重载在类中定义多个同名的方法,但是每一个同名的方法要求不同数据类型和不同参数


    下面来实现一个方法重载 以ArrayList 为例

    可以查看数据
    可以删除数据 删除可以通过id 或者对象删除
    可以获取数据

    class ArrayList{
    
    	// 此处为简写	
      constructor(public element: Array<object>){}
    /**
    不使用简写为
      public element:Array<Object>;
      constructor(element_:Array<Object>){
        this.element = element_
      }
    */
    
      /**
       * 获取某一个值
       * @param index 
       * @returns 
       */
      get(index:number){
        return this.element[index]
      }
      // 显示值
      show(){
        this.element.forEach(i=>console.log(i))
      }
    
      // 实现删除方法重载
      remove(val:number):number
      remove(val:Object):Object
      remove(val:number | Object){
        this.element = this.element.filter((e,index)=>{
        
          if(typeof val === 'number'){
              return val !== index
          }else{
            return val !== e
          }
        })
      return val;
      }
    
    }
    let a = {name:'zixia',age:12},b= {name:'selfsummer',age:88},c= {name:'自夏',age:18}
    
    let newAr = new ArrayList([a,b,c]);
    
    // console.log(newAr.get(0))
    // newAr.show()
    
    
    console.log('删除的值',newAr.remove(c))
    // newAr.show()
    

    函数重载

    函数重载或者方法重载适用于某个功能一样,但是细节有不一样
    比如说一个函数有多个参数,每一个参数代表不通意义 你个时候就可用使用函数重载

    函数重载的定义
    1. 一个或多个签名组合叫做函数重载
    2. 外部调用函数重载时,稚嫩调用重载的前面 (函数体前面的叫做签名)不能够调用调用使用的函数签名(这个是TS规定的)
    3. 调用函数重载时会根据传递的参数来判定调用的那个函数
    4. 只有一个函数体吗,只有实现签名配备课函数体,所有重载签名签名只有签名,没有配置函数体

    数据定义 以及类型定义

    
    type MessageType = 'Image' | 'audio' | 'video' | string;
    type Message = {
    	id: number;
    	type: MessageType;
    	sendMessage: string;
    };
    
    // message:Array<Message>  同等下面
    let messageList: Message[] = [
    	{
    		id: 1,
    		type: 'video',
    		sendMessage: '视频视频',
    	},
    	{
    		id: 2,
    		type: 'audio',
    		sendMessage: '我是消息',
    	},
    	{
    		id: 3,
    		type: 'video',
    		sendMessage: '视频视频',
    	},
    
    	{
    		id: 4,
    		type: 'msg',
    		sendMessage: 'msgmsh',
    	},
    	{
    		id: 5,
    		type: 'Image',
    		sendMessage: '图片图片',
    	},
    ];
    

    不使用函数重载 使用联合数据类型

    function getMessage(
    	value: number | MessageType
    ): Message | Array<Message> | undefined {
    	if (typeof value === 'number') {
    		// find 查找数据对应得某一条 返回翻个
    		return messageList.find((tyep) => value === tyep.id);
    	} else {
    		// 返回的是数组
    		return messageList.filter((tyep) => tyep.type === value);
    	}
    }
    
    // console.log(getMessage('video'));  {id: 1,type: 'video',	sendMessage: '视频视频',	}
    
    
    // 现在需求是 可以找返回的具体某一个字段
    // 使用联合类型转换 把getMessage返回类型转化为 Message 这里是上面定义得
    // 这里调用方法需要传递 number 类型得 因为find 返回得是一个对象  filter 返回的是一个数组
     let msg = (<Message>getMessage(1)).sendMessage;
     console.log(msg);
    

    函数重载

    function loadMessage(value:number):Message; // 重载签名有多个
    function loadMessage(value:MessageType):Message[];// 重载签名
    // function loadMessage(value:string):Message[] | Message |undefined{ // 第一个重载函数会报错 ,因为产书限定是 string (出错规则是根基第一个签名来匹配参数)
    // function loadMessage(value:number):Message[] | Message |undefined{ // 第二个重载函数会报错 ,因为产书限定是 string (出错规则是根基第一个签名来匹配参数)
    function loadMessage(value:string|number):Message[] | Message |undefined{ // 正确
      if (typeof value === 'number') {
    		// find 查找数据对应得某一条 返回翻个
    		return messageList.find((tyep) => value === tyep.id);
    	} else {
    		// 返回的是数组
    		return messageList.filter((tyep) => tyep.type === value);
    	}
    }
    // 按住ctrl + 鼠标左键会定位到 直接对应类型的函数签名
    
    //此函数返回的 Message 数据类型 所有可通过点来获取值
    loadMessage(1).sendMessage;
    
    // 此处返回的是Message[] 数据类型 所有能调用数组的所有方法
    const infoMas = loadMessage('video');
    infoMas.forEach(i=>{console.log(i)})
    

    函数重载签名时候 多个参数不一致时

    
    function newMessage(value:number):Message; // 重载签名有多个
    function newMessage(value:MessageType,pageCont:number):Message[];// 重载签名
    // function newMessage(value:string|number,pageCont:number = 1):Message[] | Message |undefined{ // 正确
    
    // function newMessage(value:string|number,pageCont?:number):Message[] | Message |undefined{ // 正确
    function newMessage(value:string|number,pageCont:number = 1){  // 这个可用省略返回数据类型,这里会进行类型推断,(PS 我猜这里应该是上面的重载签名有返回类型吧)
      if (typeof value === 'number') {
    		// find 查找数据对应得某一条 返回翻个
    		return messageList.find((tyep) => value === tyep.id);
    	} else {
    		// 返回的是数组
    		return messageList.filter((tyep) => tyep.type === value).splice(0,pageCont)
    	}
    }
    // 按住ctrl + 鼠标左键会定位到 直接对应类型的函数签名
    
    //此函数返回的 Message 数据类型 所有可通过点来获取值
    loadMessage(1).sendMessage;
    
    // 此处返回的是Message[] 数据类型 所有能调用数组的所有方法
    const infoMasnew = newMessage('video',2);
    infoMas.forEach(i=>{console.log(i)})
    

    构造器重载

    构造器重载和函数重载使用基本相同,主要区别是:TS类构造器重载签名和实现签名都不要管理返回值(也没有返回值),TS构造器是在对象创建出来之后还没有赋值给对象变量之前执行,一般采用给对象属性赋值

    构造器是在对象创建的整个过程中被使用到的,当对象创建完成后就不会使用到,构造器可以说成是构造函数,但是不能看做是方法

    ts 和es6 的class 中的this 当new 一个对象时,构造器会隐式返回this 给对象等号左边的对象变量,this
    和等号左边的对象都指向当前创建正在创建的对象 类会隐式返回this,如果要说 类有返回值那也只能是this


    需求:根据传入的宽高计算面积 参数可为二个实参 可以为一个对象实参
    type TypeSummation= {
      width?:number;
      height?:number;
    }
    
    class summation {
    
      public width;
      public height;
      constructor(width: number, height: number)
      constructor(ParamObje_:TypeSummation)
      // constructor(summationObj:any,height_?:number){ // 因为这个height_ 上面是构造器重载是必填参数 所以这里不建议使用可选参数
      constructor(ParamObje_Obj_:any,height_=0){
        if(typeof ParamObje_Obj_ === "object"){
          const {width,height} = ParamObje_Obj_;
    
          this.width = width;
          this.height = height;
        }else{
          this.width=ParamObje_Obj_;
          this.height = height_;
        }
      }
    
      sunArea():number{
        return this.width*this.height
      }
    
    }
    
    const sun = new summation(40,50);
    
    console.log(sun.sunArea());
    
    const obj:TypeSummation={width:10,height:20}
    
    console.log(new summation(obj).sunArea());
    
    展开全文
  • 函数重载、运算符重载1.函数重载2.运算符重载 1.函数重载 1.1函数重载的定义 函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)...

    函数重载、运算符重载

    1.函数重载

    1.1函数重载的定义
    函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同。
    1.2使用场景
    常用来处理实现功能类似数据类型不同的问题。

    下面举例来说明一下重载函数的格式。

    int Add(int left,int right){
        return left + right;
    }
    double Add(double left, double right)
    {
    	return left + right;
    }
    long Add(long left, long right)
    {
    	return left + right;
    }
    int main()
    {
    	Add(10, 20);
    	Add(10.0, 20.0);
    	Add(10L, 20L);
    	return 0;
    }
    

    上面的代码就是对Add函数就行了重载,解决不同类型的加法问题。
    下面的两个函数不属于函数重载,从定义上来看,同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同。这两个函数只是返回值类型不同,参数列表完全相同,与重载函数根本不是一回事,所以下面两个函数不属于函数重载

    int Add(short left, short right){
        return left + right;
    }
    short Add(short left, short right)
    {
    	return left + right;
    }
    

    为什么C++支持函数重载,而C语言不支持函数重载呢?
    在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
    在这里插入图片描述在这里插入图片描述
    1.通过我们C语言阶段学习的编译链接,可以知道,当前a.cpp中调用了b.cpp中定义的Add函数时,编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。
    2. 链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。
    3. 链接时,面对Add函数,链接器会使用编译器中自己的函数名修饰规则。

    因为Windows下vs的修饰规则过于复杂,这里就不做演示了,直接告诉大家结论

    C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,即支持重载。

    2.运算符重载

    2.1运算符重载的定义
    运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
    2.2运算符重载的特性
    C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
    函数名字为:关键字operator后面接需要重载的运算符符号。
    函数原型:返回值类型 operator操作符(参数列表)
    这里用自定义Data类型来简单演示一下运算符重载

    class Date
    {
    public:
    
    	 Date(int year = 1900)
    		//对当前对象中的成员变量进行初始化
    		: _year(year)
    		, _month(1)
    		, _day(1)
    
    	{
    	}
    	Date& operator=(const Date& d) {  //这里重载了赋值运算符
    		cout << this << "=" << &d << endl;
    		if (this != &d) {
    			_year = d._year;
    			_month = d._month;
    			_day = d._day;
    		}
    	}
    private:
    
    	int _year;
    	int _month;
    	int _day;
    
    };
    int main()
    {
    	Date d1(2020);
    	d1 = 2021;//  调用了赋值运算符重载
    	return 0;
    }
    

    2.3运算符重载需要注意的几点

    • 不能通过连接其他符号来创建新的操作符:比如operator@
    • 重载操作符必须有一个类类型或者枚举类型的操作数
    • 内置类型的操作符,不能改变其含义
    • 作为类成员的重载函数时,其形参看起来比操作数数目少1,是因为成员函数的操作符有一个默认的形参this,限定为第一个形参
    • .* 、:: 、sizeof 、?: 、. 这5个运算符不能重载
    展开全文
  • 主要介绍了Python函数重载,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 函数 重载

    2021-11-15 18:31:10
    1.什么是函数重载? 函数重在是指在同一个作用域内,有多个函数名相同,但是形参列表不同(参数类型不同,参数个数不同,参数顺序不同),返回值无关,我们将这种叫做重载函数。重载的函数是通过形参列表区分的,和...
  • 里面详细解释了函数重载,以及如何应用函数重载。。。。
  • 本文实例讲述了PHP利用func_get_args和func_num_args函数实现函数重载的方法。分享给大家供大家参考。具体方法分析如下: 学习php的朋友都知道php本身是没有函数重载这一说的,更没说像java,c那样使用方法,但如果...
  • 主要介绍了C++函数重载详解及实例代码的相关资料,需要的朋友可以参考下
  • C++构造函数重载

    2013-04-02 19:25:45
    重载构造函数,调用成员函数,供C++初学者理解构造函数重载的概念
  • TS 函数重载

    千次阅读 2021-07-08 15:03:28
    在实现某个功能的时候, 要写一个时间转换的函数, 大概就是传递一个Moment对象进去, 然后给我返回一个格式为YYYY-MM-DD HH:mm:ss的字符串, 如果参数是undefined, 就不做处理,返回undefined; 然后写了这样一...
  • JavaScript支持函数重载吗?可以说不支持,也可以说支持。说不支持,是因为JavaScript不能好像其它原生支持函数重载的语言一样,直接写多个同名函数,让编译器来判断某个调用对应的是哪一个重载。说支持,是因为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 523,426
精华内容 209,370
关键字:

函数重载

友情链接: PSD.m.zip