• 函数重载分析


    1. 函数重载

    函数重载,指的是用同一个函数名搭配不同的参数,从而定义不同的函数。
    重载函数在本质上是相互独立的不同函数,它们的函数类型不同
    函数重载至少需要满足下面三个条件之一

    • 参数个数不同
    • 参数类型不同(指的是显式类型,不包括隐式类型转换,如int和char属不同类型)
    • 参数顺序不同

    下面是函数重载的一些注意事项

    • 函数重载是由函数名和参数列表决定的
    • 函数返回值不能作为函数重载的依据
    • 函数重载必然发生在在同一个作用域中
    #include <stdio.h>
    
    void func(int a)
    {
        printf("void func(int a)
    ");
    }
    
    void func(char a)
    {
        printf("void func(char a)
    ");
    }
    
    char func(int a, int b)
    {
        printf("char func(int a, int b)
    ");
        return 'a';
    }
    
    int *func(int a, char c)
    {
        printf("int *func(int a, char c)
    ");
        return NULL;
    }
    
    int func(char c, int a)
    {
        printf("int func(char c, int a)
    ");
        return 0;
    }
    
    int main()
    {
        func(1);
        func('a');
        func(1, 2);
        func(1, 'a');
        func('a', 1);
    
        return 0;
    }
    

    /*
     * 打印重载函数的地址,证明其本质是互不相同的函数
    */
    
    #include <stdio.h>
    
    int add(int a, int b)        // 函数类型为int(int, int)
    {
        return a + b;
    }
    
    int add(int a, int b, int c) // 函数类型为int(int, int, int)
    {
        return a + b + c;
    }
    
    int main()
    {
        printf("%p
    ", (int(*)(int, int))add);  //打印add入口地址时,根据函数类型进行强制类型转换
        printf("%p
    ", (int(*)(int, int, int))add);
    
        return 0;
    }
    

    通过输出结果,可以看出构成重载的两个func函数地址不同,说明重载函数的本质确实是相互独立的不同函数。

    2. 函数重载与函数默认参数

    当函数默认参数遇上函数重载,会发生什么?下面的代码,C++编译器如何选择调用哪一个func?

    #include <stdio.h>
    
    int func(int a, int b, int c = 0)
    {
        return a * b * c;
    }
    
    int func(int a, int b)
    {
        return a + b;
    }
    
    int main(int argc, char *argv[])
    {
        int c = func(1, 2);  //which one?
    
        return 0;
    }
    

    从编译结果看以看出,C++编译器也不知道该如何选择了,因此直接报错:第15行对重载函数func的调用是模糊的、不明确的,因为有两个可选的函数。

    我们来分析下编译器调用重载函数的准则

    • 将所有同名函数作为候选者
    • 尝试寻找可行的候选函数
    • 精确匹配实参
    • 通过默认参数匹配实参
    • 通过默认类型转换匹配实参
    • 匹配失败
    • 最终找到的候选函数不唯一,出现二义性,编译失败
    • 没有匹配到任何候选函数,函数未定义,编译失败

    上述示例代码,就是由于匹配结果出现了二义性,而导致的编译失败。

    3. 函数重载与函数指针

    将重载函数名赋值给函数指针时

    • 根据重载规则挑选与函数指针参数列表一致的候选者
    • 严格匹配候选者的函数类型与函数指针的函数类型
    • 无法直接通过函数名得到重载函数的入口地址
    #include <stdio.h>
    #include <string.h>
    
    int func(int x)
    {
        return x;
    }
    
    int func(int a, int b)
    {
        return a + b;
    }
    
    int func(const char *s)
    {
        return strlen(s);
    }
    
    typedef int(*PFUNC1)(int a);
    typedef int(*PFUNC2)(int a, int b);
    typedef int(*PFUNC3)(const char *s);
    typedef void(*PFUNC4)(const char *s);
    
    int main(int argc, char *argv[])
    {
        PFUNC1 p1 = func;
        PFUNC2 p2 = func;
        PFUNC3 p3 = func;
        PFUNC4 p4 = func;
    
        printf("%d
    ", p1(1));
        printf("%d
    ", p2(1, 2));
        printf("%d
    ", p3("hello world"));
    
        return 0;
    }
    

    编译第29行报错,根据匹配规则,第一步匹配到int func(const char *s),第二步匹配函数类型失败,不存在函数类型为void(*)(const char *)的func。
    注释掉第29行,再次编译运行结果如下。

  • 相关阅读:
    利用 StartLoadingStatus 和 FinishLoadingStatus 读取数据特别是大数据时增加渐隐渐显等待特效
    在Indicator中添加动态Checkbox,无需绑定数据源,支持全选
    修复DBGrideh使用TMemTableEh在Footers求平均值为0的Bug
    字符串操作之格式化
    关于C#里面SQLite读取数据的操作
    多线程“尚未调用coinitialize” 报错
    自动化脚本运行稳定性(一)——脚本健壮性
    接口测试用例编写规范
    测试计划对应用质量的影响
    MySQL数据操作语句精解
  • 原文地址:https://www.cnblogs.com/songhe364826110/p/11581635.html
Copyright © 2020-2023  润新知