首页 > 编程语言 >C++ --- 函数重载

C++ --- 函数重载

时间:2023-12-23 17:24:42浏览次数:28  
标签:0000000000000000 int double C++ --- DEFAULT func 重载 LOCAL

什么是函数重载

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

函数重载是C++在C语言基础上进行的改进,解决了C语言同名函数无法服务不同类型的参数的问题,在C中,实现整型加法和浮点加法无法使用名字相同的Add函数,只能给这两个函数的实现分别取名为Addi和Addd

函数重载还为操作符重载提供了可能

使用函数重载有如下几个要点:

  • 必须是在同一作用域下的同名函数才能重载
int func(int a, int b)       // 全局域func
{
    return a + b;
}
 
namespace myspace            // myspace域func
{
    int func(int a, int b)
    {
        return a * b;
    }
 
    double func(double a, double b)
    {
        return a + b;
    }
}

其中,全局域函数int func(int int)和myspace域函数int func(int int)和double func(double double)均不构成函数重载,而myspace域内部的函数int func(int int)和double func(double double)属于同一作用域且函数名相同,构成函数重载

  • 形参的类型不同 
## 构成函数重载的类型1————形参类型不同
 
int func(int a, int b)            // 形参类型是int
{
    return a + b;
}
 
double func(double a, double b)   // 形参类型是double
{
    return a + b;
}
  • 形参的个数不同 
## 构成函数重载的类型2————形参个数不同
 
double func(double a, double b)            // 形参个数为2
{
    return a + b;
}
 
double func(double a, double b, double c)  // 形参个数为3
{
    return a + b;
}
  • 形参的顺序不同
## 构成函数重载的类型3————形参的顺序不同
 
void func(int a, char b)
{
    // do test
}
 
void func(char a, int b)
{
    // do test
}

值得注意的是,返回值不同不构成函数重载,如下面这两个函数——在调用函数Add时,编译器无法根据返回值区分究竟应该调用哪个函数,报错为" 无法重载仅按返回类型区分的函数 "

short Add(short a, short b)   
{
    return a + b;
}
 
int Add(short a, short b)
{
    return a + b;
}

函数重载在C++编译器实现原理

我们知道,一个C程序要经过预处理,编译,汇编,链接将一个.c文件变成可执行文件,其中在编译过程会生成符号表,在链接过程经过符号解析和重定位完成对输入模块内所有符号地址的确认

对于下面的c程序

## test.c
 
int func(int a, int b)
{
    return a + b;
}
 
double func1(double a, double b)
{
    return a + b;
}
 
int main()
{
    return 0;
}

我们知道C中是不支持函数重载的,这是因为C中的符号表不会对函数名进行修饰,使用readelf命令打开test.o,得到的符号表如下,可以看到函数func和func1在符号表中的名字就是其本身,因此如果是两个同名符号,那么在符号表中会出现同名符号,这对于编译器来说是不可接受的,在编译阶段就会出现错误

Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     8: 0000000000000000    20 FUNC    GLOBAL DEFAULT    1 func  // 函数func的名称
     9: 0000000000000014    44 FUNC    GLOBAL DEFAULT    1 func1 // 函数func1的名称
    10: 0000000000000040    11 FUNC    GLOBAL DEFAULT    1 main

同样,对于下面一段C++代码

## test.cpp
 
typedef struct ListNode
{
    ListNode* next;
    int val;
}LTNode;
 
int func(int a, int b)
{
    return a + b;
}
 
double func(double a, double b)
{
    return a + b;
}
 
void func(int a, char b)
{}
 
void func(LTNode* p1, int a)
{}
 
int main()
{
    return 0;
}

C++支持函数重载,我们使用g++ -c 对test.cpp文件进行编译得到test.o,使用readelf得到的符号表如下所示

Symbol table '.symtab' contains 21 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.cpp
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     1 OBJECT  LOCAL  DEFAULT    4 _ZStL8__ioinit
     6: 0000000000000066    61 FUNC    LOCAL  DEFAULT    1 _Z41__static_initializati
     7: 00000000000000a3    21 FUNC    LOCAL  DEFAULT    1 _GLOBAL__sub_I__Z4funcii
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
    10: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 
    11: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
    12: 0000000000000000    20 FUNC    GLOBAL DEFAULT    1 _Z4funcii     // 函数int func(int int)
    13: 0000000000000014    44 FUNC    GLOBAL DEFAULT    1 _Z4funcdd     // 函数double func(double double)
    14: 0000000000000040    14 FUNC    GLOBAL DEFAULT    1 _Z4funcic     // 函数void func(int char)
    15: 000000000000004e    13 FUNC    GLOBAL DEFAULT    1 _Z4funcP8ListNodei // 函数void func(LTNode* int)
    16: 000000000000005b    11 FUNC    GLOBAL DEFAULT    1 main
    17: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev
    18: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN   UND __dso_handle
    19: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev
    20: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __cxa_atexit

我们发现,对于每个func,在符号表中都不再是以func作为名称,而是加上了一些修饰 

int func(int a, int b) —— _Z4funcii
double func(double a, double b) —— _Z4funcdd
void func(int a, char b) —— _Z4funcic
void func(LTNode* p1, int a) —— _Z4funcP8ListNodei

C++中函数名的修饰规则是——返回类型+函数名+参数列表 ,返回类型不构成函数重载,所以这里不对其进行研究,函数名以红色标出,紧跟在后面的是参数列表(ii,dd,ic),自定义的类型(这里的ListNode)后面同样跟自定义的类型名(ListNode和i)

通过函数名修饰,C++可以区分同名函数,实现函数重载

extern "C"

有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。比如:tcmalloc是google用C++实现的一个项目,他提供tcmallc()和tcfree两个接口来使用,但如果是C项目就没办法使用,那么他就使用extern “C”来解决

例如,下面的C程序要调用C++目标文件func.o中的func函数

#include <stdio.h>
 
int func(int a, int b);     // func的声明,func的定义在func.o中
 
int main()
{
    printf("%d\n", func(1, 2));
}

func.cpp及其对应的符号表

int func(int a, int b)
{
    return a + b;
}
 
 
Symbol table '.symtab' contains 9 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS func.cpp
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     8: 0000000000000000    20 FUNC    GLOBAL DEFAULT    1 _Z4funcii

func被修饰成_Z4funcii,因此在链接时,C程序会按照func进行符号解析,发现找不到func函数,给出一个链接错误,而如果使用extern "C"将告诉C++编译器,按照C的函数名规则来进行符号解析,得到的符号表里的func是按照C风格修饰的func,此时链接时,C程序就能正确找到func完成链接工作

extern "C"
{
    int func(int a, int b)
    {
        return a + b;
    }
}
 
 
Symbol table '.symtab' contains 9 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS func.cpp
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     8: 0000000000000000    20 FUNC    GLOBAL DEFAULT    1 func

 

标签:0000000000000000,int,double,C++,---,DEFAULT,func,重载,LOCAL
From: https://www.cnblogs.com/god-of-death/p/17923330.html

相关文章

  • 模拟集成电路设计系列博客——4.3.2 双晶体管MOSFET-C积分器
    4.3.2双晶体管MOSFET-C积分器MOSFET-C滤波器类似于全差分有源RC滤波器,除了电阻被等效的线性区MOS晶体管所取代。由于有源RC和MOSFET-C滤波器紧密关联,对于设计者来说,一个好处就是可以大量使用在有源RC滤波器上的已有知识。本小节我们讨论双晶体管MOSFET-C积分器。一个双晶体管MO......
  • C++U5-11-特殊二叉树
    学习目标 完全二叉树:二又树拥有的性质,在完全二叉树中都拥有 性质 练习1 练习2 练习3编程题:[完全二叉树的叶子结点]【算法分析】递归,前序遍历输出。【参考代码】#include<iostream>usingnamespacestd;constintSIZE=1010;structnode{......
  • 前端项目练习(一) ---美食美客网页制作
    项目名称:美食美客网页制作技术栈:HTML+ CSS背景:熟悉使用HTML、CSS的使用一、HTML代码1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<metaname="viewport"content="width=device......
  • 6.简单句-句子的成分——宾语表语
    宾语:名词代词非谓语动词从句 表语名词充当标语——Iamateacher代词——I aminChongqin非谓语动词——Mydreamistobecomeapoet./Mydreamis becomingapoet.从句——adj——介词短语作表语—— eg.IlileinChongqing(错,Like是实义动词)I......
  • 设计模式<c++> (1)策略模式
    一、定义策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。二、使用场景客户需要很多种鸭子。要求:1.每种鸭子都要会游泳。2.每种鸭子有叫和飞的行为。3.鸭子的叫和飞的行为可以在使用......
  • 2023-12-23训练总结
    T1计数ProblemDescriptionInputOutputSampleInputCopy210SampleOutputCopy90DataConstraint忘记初始化了调了半个小时。维护\(f_{i,0/1}\)表示长度为\(i\),最高位为\(0\)/不为\(0\)的合法方案数。明显有:\[f_{i,0}\getsf_{i-1,1}\\f_{i,1}\g......
  • 简化版本 SQL-Minus 解释器
    先扔一下我们伟大的助教提供的题面。注:以下做法仅供娱乐,大多数都十分复杂且低效,请尽量不要尝试。CREATETABLE考虑实现一个array<ValEx>。初始化时由于字段数未知,需要实现一个list<ValEx>来支持插入,最后将其转为array<ValEx>。INSERT考虑实现一个vector<array<Val>>。......
  • ICEE-SPI-debug最好用 SPI 和 JTAG 或更优的(高达104MHz的)SPI通信保障飞速的debug响
    S25FL032P:32-MbitCMOS3.0VoltFlashMemorywith104-MHzSPI(SerialPeripheralInterface)MultiI/OBusSPANSIONZentelSDRAM;https://www.zerodayinitiative.com/blog/2019/9/2/mindshare-hardware-reversing-with-the-tp-link-tl-wr841n-routerhttps://openw......
  • 2023-12-23:用go语言,一支n个士兵的军队正在趁夜色逃亡,途中遇到一条湍急的大河 敌军在T
    2023-12-23:用go语言,一支n个士兵的军队正在趁夜色逃亡,途中遇到一条湍急的大河敌军在T的时长后到达河面,没到过对岸的士兵都会被消灭现在军队只找到了1只小船,这船最多能同时坐上2个士兵。当1个士兵划船过河,用时为a[i]当2个士兵坐船同时划船过河时,用时为max(a[j],a[i])两士兵中用时最......
  • DB207S-ASEMI迷你贴片整流桥DB207S
    编辑:llDB207S-ASEMI迷你贴片整流桥DB207S型号:DB207S品牌:ASEMI封装:DBS-4最大平均正向电流:2A最大重复峰值反向电压:1000V产品引线数量:4产品内部芯片个数:4产品内部芯片尺寸:55MIL峰值正向漏电流:<10ua恢复时间:>2000ns浪涌电流:50A芯片材质:光阻GPP最大正向电压:1.10V工作结温:-55℃~150℃包装......