C++中的函數重載分析(二)

1,重載與指針:編程

    1,下面的函數指針將保存哪一個函數的地址?      ide

 1 int func(int x)
 2 {
 3      return x;
 4 }
 5 
 6 int func(int a, int b)
 7 {
 8     return a + b;
 9 }
10 
11 int func(const char* s)
12 {
13     return strlen(s);
14 }
15         
16 typedef int(*PFUNC)(int a);
17 int c = 0;
18 PFUNC p = func;
19 c = p(1);  // which function to call ?

    2,重載函數的函數名不表明函數的入口地址,要加入相應的函數類型方可;函數

 

2,函數重載趕上函數指針:測試

    1,將重載函數名賦值給函數指針時:spa

       1,根據重載規則挑選與函數指針參數列表一致的候選者;指針

       2,嚴格匹配候選者的函數類型與函數指針的函數類型;code

           1,比重載更加嚴格,也要加上返回值類型的匹配;blog

           2,不進行任何形式的默認類型轉換;作用域

 

3,函數重載 VS 函數指針編程實驗:編譯器

    1,main.cpp 文件: 

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int func(int x)
 5 {
 6     return x;
 7 }
 8 
 9 int func(int a, int b)
10 {
11     return a + b;
12 }
13 
14 int func(const char* s)
15 {
16     return strlen(s);
17 }
18 
19 typedef int(*PFUNC)(int a); //typedef double (*PFUNC)(int a) 時錯誤;
20 
21 int main(int argc, char *argv[])
22 {
23     int c = 0;
24 
25     PFUNC p = func;
26         
27     c = p(1);   
28     
29     printf("c = %d\n", c);
30 
31     return 0;
32 }

2,輸出結果:

  1

 

4,注意:

    1,函數重載必然發生在同一個做用域中;

       1,C++ 中不止一個做用域,還有類做用域等;

       2,C 只有一個全局做用域;

    2,編譯器須要用參數列表或函數類型進行函數選擇;

       1,重載時,若是不碰到指針,則用參數列表選擇,若是碰到指針,則用函數類型來選擇;

    3,沒法直接經過函數名獲得重載函數的入口地址;

       1,強制類型轉換爲函數指針能夠;

 

5,C++ 和 C 相互調用:

    1,實際工程中 C++ 和 C 代碼相互調用是不可避免的;

        1,項目中決定採用 C++ 的時候,也極可能會調用舊的用 C 代碼編寫的代碼,這時就涉及到 C++ 調用 C 代碼;

        2,C++ 編譯器編譯 C 的源碼能夠直接經過,可是工程中有一些 C 代碼被編譯成目標文件,至關於在 C++ 中會用到用 C 語言編寫和編譯的第三 方的庫,這些第三方庫仍是要收費的,既然收費了,就要合理的利用;

        3,見以下示例:

            1,add.h 文件: 

1 int add(int a, int b);

            2,add.c 文件: 

1 #include "add.h" //不能用 #include <add.h>,不然找不到 add.h 文件,這裏不用包含這個文件以及定義 1 中的 add.h 頭文件也能夠編譯經過,可是後續的使用這個函數就只能包含源碼,因此仍是要調用頭文件;
2 
3 int add(int a, int b)
4 {
5     return a + b;
6 }

         3,用 gcc -c add.c -o add.o 編譯生成 add.o 文件;

         4,在 main.c 文件中調用:

 1 #include <stdio.h>
 2 #include "add.h"
 3 
 4 int main()
 5 {
 6     int c = add(1, 2);
 7     
 8     printf("c = %d\n", c);
 9     
10     return 0;
11 }

       5,經過 g++ main.cpp add.o(第三方庫不提供源代碼,只提供頭文件和編譯生成的目標文件) 命令編譯器顯示:undefin dreference    to 'add(int, int)';

       6,經過符號表命令 nm 查閱 nm add.o 獲得: 00000000 T add,說明符號表中已經有 add 函數了;

       7,由於用 C++ 編譯器調用 C 編譯器編譯的代碼,不能成功;

    2,C++ 編譯器可以兼容 C 語言的編譯方式;

        1,C++ 天生須要兼容 C;

        2,C++ 和 C 編譯方式是不一樣的,C++ 編譯器可以兼容 C 語言編譯方式, 可是有優先級問題;

    3,C++ 編譯器會優先使用 C++ 編譯的方式;

    4,extern 關鍵字能強制讓 C++ 編譯器進行 C 方式的編譯;

        1,代碼示例:

1 extern "C"  // 告訴編譯器大括號中的代碼以 C 方式編譯;
2 {
3     // do C-style compilation here,能夠有不一樣的多個函數;
4 }

        2,更改 main.cpp 文件以下:   

 1 #include <stdio.h>
 2     
 3 extern "C"
 4 {
 5     #include "add.h"
 6 }
 7 
 8 int main()
 9 {
10     int c = add(1, 2);
11         
12         printf("c = %d\n", c);
13 
14     return 0;
15 }

 

6,C++ 調用 C 函數編程實驗:

    1,見本博客 5.4.2內容;

 

7,問題:

    1,如何保證一段 C 代碼只會以 C 的方式被編譯?

       1,不能直接調用 extern "C",由於這是 C++ 中才有的,C 語言中不支持這樣的寫法,此處是一段 C 代碼無論在 C 編譯器仍是 C++ 編譯器都只以 C 方式編譯,因此就要在 C 代碼中來入手;

       2,若是在 C 編譯器中編譯帶有 extern "C" 的代碼,則會報錯,在 C++中不會,報錯的內容爲「expected identifier(標識符) or '(' before          string constant」;

 

8,解決方案:

    1,_cplusplus 是 C++ 編譯器內置的標準宏定義;

       1,測試當前的編譯器是否爲 C++ 編譯器,由於在 C 編譯器內部不含有這個宏;

    2,_cplusplus 的意義:

       1,確保 C 代碼以統一的 C 方式被編譯成目標文件; 

       2,#ifdef _cplusplus  // 判斷是否爲 C++ 編譯器;   

1 #ifdef _cplusplus  // 判斷是否爲 C++ 編譯器;
2 extern "C" {  // 保存這一行代碼;
3 #endif
4         
5 // C-style Compilation here
6 
7 #ifdef _cplusplus  // 判斷是否爲 C++ 編譯器;
8 }  // 保存這一行代碼;
9 #endif

 

9,注意事項:

    1,C++ 編譯器不能以 C 的方式編譯重載函數;

       1,編譯方式可以決定函數名被編譯後的目標名是什麼;

    2,編譯方式決定函數名被編譯後的目標名:

       1,C++ 編譯方式將函數名和參數列表編譯成目標名;

       2,C 編譯方式只將函數名做爲目標名進行編譯;

 

10,小結:

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

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

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

       1,extern "C" 代碼塊中不能出現重載函數;

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

相關文章
相關標籤/搜索