C++ 函數重載分析

一、重載的概念

重載(Overload)c++

  • 同一個標識符在不一樣的上下文有不一樣的意義

二、C++中的函數重載

函數重載(Function Overload)函數

  • 用同一個函數名定義不一樣的函數
  • 當函數名和不一樣的參數搭配時函數的含義不一樣
int func(int x)
{
    return x;
}
int func(int a, int b)
{
    return a+b;
}
int func(const char* s)
{
    return strlen(s);
}

函數重載至少知足下面的一個條件:工具

  • 參數個數不一樣
  • 參數類型不一樣
  • 參數順序不一樣
int func(int a, const char* s)
{
    return a;
}
int func(const char* s, int a)
{
    return strlen(s);
}
// 能夠發生重載

當函數默認參數於函數重載發生做用測試

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 c = func(1, 2);    // Which one?
    // 直接報錯,特性參數衝突
    return 0;
}

編譯器調用重載函數的準則指針

  • 將全部同名函數做爲候選者
  • 嘗試尋找可行的候選函數code

    • 精確匹配實參
    • 經過默認參數可以匹配實參
    • 經過默認類型轉換匹配實參
  • 匹配失敗作用域

    • 最終尋找到的候選函數不惟一,則出現二義性,編譯失敗
    • 沒法匹配全部候選者,函數未定義,編譯失敗

函數重載的注意事項:編譯器

  • 重載函數在本質上是相互獨立的不一樣函數
  • 重載函數的函數類型不一樣
  • 函數返回值不能做爲函數重載的依據

函數重載是由函數名參數列表決定的,函數重載與返回值沒有關係string

證實函數重載是兩個不一樣的函數:io

#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\n", (int(*)(int, int))add);
    printf("%p\n", (int(*)(int, int, int))add);

    // 發現函數的入口地址是不一樣的,因此是兩個不一樣的函數
    
    return 0;
}
// 結果:
// 00DF100A
// 00DF100F
// 意味着這兩個函數的入口地不一樣,反向證實了這兩個函數是不用的函數

也能夠經過vs自帶工具, dumpbin 命令,查看符號表SYMBOLS

034 00000000 SECT4  notype ()    External     | ?add@@YAHHH@Z (int __cdecl add(int,int))
035 00000000 SECT6  notype ()    External     | ?add@@YAHHHH@Z (int __cdecl add(int,int,int))

編譯器獲得的這兩個函數的標識是不同的

重載函數的本質是兩個不一樣的函數

三、重載與指針

分析下面的函數將保存哪一個函數的地址

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(*PFUNC)(int a);
int c = 0;
PFUNC p = func;
c = p(1);

函數重載趕上函數指針,將重載函數名賦值給函數指針時:

  • 根據重載規則挑選與函數指針參數列表一致的候選者
  • 嚴格匹配候選者的函數類型與函數指針的函數類型
函數類型包括了返回值類型
#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(*PFUNC)(int a);            // 定義了一個函數指針
// typedef void(*PFUNC)(int a);        // 返回值類型不匹配
// typedef double(*PFUNC)(int a);    // 返回值類型不匹配
int main(int argc, char *argv[])
{
    int c = 0;

    PFUNC p = func;    
        
    c = p(1);   
    
    printf("c = %d\n", c);

    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\n", add);    // 直接打印函數名地址,沒法匹配函數
    
    printf("%p\n", (int(*)(int, int))add);    // 這實際上是一個強制類型轉換,轉換成了一個函數指針類型,就會進行嚴格的函數類型匹配
    printf("%p\n", (int(*)(int, int, int))add);

    return 0;
}

四、C++和C相互調用

實際工程中C++和C代碼相互調用是不可避免地,C++編譯器可以兼容C語言的編譯方式,可是會優先使用C++編譯器,extern關鍵字能強制讓C++編譯器進行C方式的編譯

extern "C"
{
    // do C-style compilation here
}

extern "c"只是針對C++來講的,C語言中不支持

怎麼樣保證C代碼不管在C++仍是C代碼中,都是用C編譯器編譯

__cplusplus是C++編譯器內置的標準宏定義

__cplusplus的意義:確保C代碼以統一的C方式被編譯成目標文件

這個宏能夠用來測試當前的編譯器是不是C++編譯器,而C語言內部沒有這個宏

#ifdef __cplusplus
extern "C"
{
#endif

// C-Style compilation
    
#ifdef __cplusplus
}
#endif

在c代碼中也是能夠調用C++代碼的

注意:

  • C++編譯器不能以C的方式編譯重載函數
  • 編譯方式決定函數名被編譯後的目標名

    • C++編譯方式將函數名參數列表編譯成目標名
    • C編譯方式只將函數名做爲目標名進行編譯

五、小結

函數重載是C++對C的一個重要升級

函數重載經過函數參數列表區分不一樣的同名函數

extern關鍵字可以實現C和C++的相互調用

編譯方式決定符號表中的函數名的最終目標名

相關文章
相關標籤/搜索