1,重載是 C 語言到 C++ 語言的一個飛躍,C 語言中沒有重載的概念,所有的函數 名是不允許有重覆的,在 C++ 中因為引進了重載,所以函數名可以重覆; 2,自然語言中的上下文: 1,你知道上面辭彙中“洗”字的含義嗎? 1,不同的動詞和名次搭配的含義是不同的; 2,結論: 1,能和“洗”字搭配的 ...
1,重載是 C 語言到 C++ 語言的一個飛躍,C 語言中沒有重載的概念,所有的函數 名是不允許有重覆的,在 C++ 中因為引進了重載,所以函數名可以重覆;
2,自然語言中的上下文:
1,你知道上面辭彙中“洗”字的含義嗎?
1,不同的動詞和名次搭配的含義是不同的;
2,結論:
1,能和“洗”字搭配的辭彙有很多;
2,“洗”字和不同的辭彙搭配有不同的含義;
3,重載(Overload)的概念:
1,重載是同一個標識符在不同的上下文有不同的意義;
2,如:
1,“洗”和不同的辭彙搭配後有不同的含義;
1,洗衣服,洗臉,洗腦,洗馬桶,...;
2,“play”和不同的單詞搭配後有不同的含義;
1,play chess, play piano, play basketball, ...;
4,思考:
1,重載在自然語言中是隨處可見的,那麼程式設計中是否也有重載呢?
1,讓程式設計語言接近自然語言,所以電腦科學家在設計語言的時候就考慮將人類的語言習慣引進到程式設計語言中,C++ 就引入了重載的概念;
2,程式設計語言中和動詞接近的是函數,所以 C++ 中選擇函數來實現重載的概念;
5,C++ 中的函數重載:
1,函數重載(Function Overload):
1,用同一個函數名定義不同的函數;
1,這是 C++ 中重載的概念;
2,C++ 後續語言也是這樣實現重載;
2,當函數名和不同的參數搭配時函數的含義不同;
1,當函數名和不同的參數搭配時實現了函數重載;
1,函數名類似動詞,參數類似名詞;
2,含義的不同在於所執行的函數體不同;
3,代碼示例:
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 }
2,函數重載初探編程實驗:
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 int main(int argc, char *argv[]) 20 { 21 printf("%d\n", func(3)); 22 printf("%d\n", func(4, 5)); 23 printf("%d\n", func("D.T.Software")); 24 25 return 0; 26 }
2,輸出結果:
3
9
12.
3,C++ 支持函數重載,它是根據自然語言中的重載概念得來的;
6,函數重載至少滿足下麵一個條件(數類序):
1,參數個數不同;
2,參數類型不同;
3,參數順序不同;
7,當函數預設參數遇上函數重載會發生什麼?
1,代碼示例:
1 int func(int a, int b, int c = 0) 2 { 3 return a * b * c; 4 } 5 6 int func(int a, int b) // 個數不同,構成重載; 7 { 8 return a + b; 9 } 10 11 int main() 12 { 13 int c = func(1, 2); // which one? 14 15 return 0; 16 }
8,函數預設參數 VS 函數重載編程實驗:
1,main.cpp 文件:
1 #include <stdio.h> 2 3 int func(int a, int b, int c = 0) 4 { 5 return a * b * c; 6 } 7 8 int func(int a, int b) 9 { 10 return a + b; 11 } 12 13 int main(int argc, char *argv[]) 14 { 15 int c = func(1, 2); // error: call of overloaded 'func(int, int)' is ambiguous 16 17 return 0; 18 }
2,這裡是 C++ 中第一個特性衝突,後續 Java、C# 語言上述的預設參數值是不允許的,因為程式設計時,不允許二義性;
9,編譯器調用重載函數的準則:
1,將所有同名函數作為候選者;
2,嘗試尋找可行的候選函數;
1,精確匹配實參;
2,通過預設參數能夠匹配實參;
3,通過預設類型轉換匹配實參;
3,匹配失敗:
1,最終尋找到的候選函數不唯一,則出現二義性,編譯失敗;
2,無法匹配所有候選者,函數未定義,編譯失敗;
10,函數重載的註意事項:
1,重載函數在本質上是相互獨立的不同函數;
2,重載函數的函數類型不同;
3,函數返回值不能作為重載的依據;
1,函數重載是由函數名和參數列表決定的;
11,函數重載的本質編程實驗:
1,main.cpp 文件:
1 #include <stdio.h> 2 3 int add(int a, int b) // 函數類型為 int(int, int); 4 { 5 return a + b; 6 } 7 8 int add(int a, int b, int c) // 函數類型為 int(int, int, int); 9 { 10 return a + b + c; 11 } 12 13 int main() 14 { 15 printf("%p\n", (int(*)(int, int))add);//函數名 add 是函數入口地址,當只用add來得到地址時,由於重載的原因,編譯器在此處顯示 error: overloaded function with no contextual information,而當不是重載的函數時,可以直接使用 add 來獲取函數地址;這裡通過強制類型轉換將 add 轉換為 (int(*)(int, int)) 這樣的函數指針; 16 printf("%p\n", (int(*)(int, int, int))add); 17 18 return 0; 19 }
2,輸出結果:
00DF100A
00DF100F
3,結論 1:
1,函數的入口地址不同,可以反向的證明這是兩個不同的函數;
4,通過 VS 命令行運行命令“dumpbin /symbols ProgramName.obj路徑”查看 VS 中的工程符號表中的如下兩行:
00E 00000000 SECT3 notype () External | ?add@@YAHHH@Z (int __cdecl add(int,int))
1,C++ 編譯器編譯 int __cdecl add(int,int) 函數後,在符號表中認為標識符為 ?add@@YAHHH@Z;
01F 00000000 SECT7 notype () External | ?add@@YAHHHH@Z (int __cdecl add(int,int,int))
1,C++ 編譯器編譯 int __cdecl add(int,int,int) 函數後,在符號表中認為標識符為 ?add@@YAHHHH@Z;
5,結論 2:
1,編譯器在編譯這兩個函數的時候,已經分開對待了,編譯器獲得的這兩個函數的名字是不同的;
2,編譯器認為這是兩個不同的函數,所以編譯出的最終結果也就是可執行程式中這兩個函數的入口地址是不同的;
6,總的結論:
1,不管正向推還是反向推,C++ 語言中重載函數的本質其實是不同的函數;
12,小結:
1,函數重載是 C++ 中引入的概念;
2,函數重載用於模擬自然語言中的辭彙搭配;
3,函數重載使得 C++ 具有更豐富的語義表達能力;
1,讓 C++ 編程更符合人類思維習慣;
4,函數重載的本質為相互獨立的不同函數;
5,C++ 中通過函數名和函數參數確定函數調用;
1,返回值不參與重載過程;