網站首頁 編程語言 正文
寫在前面
關于C語言的編譯與鏈接不懂的可以看一下下面的文章,先回顧一下以前的知識。
1 函數重載的概念
函數重載:是函數的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數,這些同名函數的形參列表(參數個數 或 類型 或 順序)必須不同,常用來處理實現功能類似數據類型不同的問題。
//1.函數的參數個數不同 #include <iostream> using namespace std; void print() { cout << "print()" << endl; } void print(int a) { cout << "print(int a)" << endl; } int main() { print(); print(1); return 0; }
執行結果如下:
print()
print(int a)
請按任意鍵繼續. . .
//2.函數的參數類型不同 #include <iostream> using namespace std; void print(double a) { cout << "print(double a)" << endl; } void print(int a) { cout << "print(int a)" << endl; } int main() { print(1.1); print(1); return 0; }
執行結果如下:
print(double a)
print(int a)
請按任意鍵繼續. . .
//3.函數的參數順序不同 #include <iostream> using namespace std; void print(double a, int b) { cout << "print(double a, int b)" << endl; } void print(int b, double a) { cout << "print(int b, double a)" << endl; } int main() { print(1.1, 1); print(1, 1.1); return 0; }
執行結果如下:
print(double a, int b)
print(int b, double a)
請按任意鍵繼續. . .
上面就是支持函數重載的三種情況,緊接著看如下兩個函數是否構成函數重載?
int Add(int num1, int num2) { return num1 + num2; } double Add(int num1,int num2) { return num1 + num2; } int main() { return 0; }
我們一編譯,編譯器就會報如下錯誤:
通過上面的分析,我們可以發現是否構成函數重載只與這些同名函數的形參列表(參數個數 或 類型 或 順序)有關,與函數的返回值的類型無關。因此返回值不同,不能構成函數重載,在調用時無法區分。
下面思考如下兩個函數是否構成函數重載?
void print(int a) { cout << "print()" << endl; } void print(int a = 0) { cout << "print(int a = 0)" << endl; }
我們一編譯,編譯器就會報如下錯誤:
因此函數參數缺省值不同,也不構成函數重載。
最后再看如下兩個函數是否構成函數重載?
void print(int a) { cout << "print()" << endl; } void print(int a = 0) { cout << "print(int a = 0)" << endl; }
很顯然上面兩個函數是構成函數重載的,我們編譯也沒有任何問題,但是我們不傳參調用就會出問題,比如print(),就會在調用時出現歧義。
2 函數重載原理
通過上面的學習,我們現在對函數重載的語法有了一定的認識和理解,緊接著我們帶著如下問題來分析一下函數重載的原理。
為什么C++支持函數重載,而C語言不支持函數重載呢?
首先我們在Linux底下創建三個文件,來驗證上面的問題,如下:
//func.h #include <stdio.h> void f(); void f(int a); //func.c void f() { printf("f()\n"); } void f(int a) { printf("f(int a)\n"); } //test.c #include "func.h" int main() { f(); f(1); return 0; }
調用C的編譯器編譯test.c和func.c就會報如下錯誤:
因此,驗證了C語言不支持函數重載。因為編譯的時候 ,兩個重載函數,函數名相同,在func.o的符號表中存在歧義和沖突。其次,鏈接的時候也存在歧義和沖突,因為它們都是用函數名去標識和查找,而重載函數,函數名相同。
為了驗證上面的說法,我們屏蔽一個函數,調用C的編譯器編譯test.c和func.c,在linux底下會生成一個a.out的可執行程序,用objdump -S 來查看一下這個文件:
同理,我們把剛屏蔽的函數取消掉,由于C++是兼容C的,因此上面的程序我們可以用C++的編譯器去編譯,其結果如下
用objdump -S 來查看一下a.out:
這里不難看出c++目標文件中的符號表中不是直接用函數名來標識和查找函數。而是引入了函數名修飾規則,不同編譯器下的函數名修飾規則不同。
g++的函數名修飾規則:_Z + 函數名長度 + 函數名 + 參數類型首字母。有了函數名修飾規則,只要函數參數不同,在func.o符號表里面重載的函數就不存在二義性和沖突了。
其次,鏈接的時候,test.o里面的main函數去調用兩個重載函數時,去符號表里面查找地址時也是明確的。
總結
原文鏈接:https://blog.csdn.net/m0_50655389/article/details/122901262
相關推薦
- 2022-07-08 C#實現IDisposable接口釋放非托管資源_C#教程
- 2022-06-01 Python正則表達式總結分享_python
- 2022-12-14 Oracle?REGEXP_LIKE模糊查詢用法例子_oracle
- 2022-12-19 C++?Boost?Coroutine使用協程詳解_C 語言
- 2022-08-25 .net?core中高效的動態內存管理方案_實用技巧
- 2022-04-03 Flutter實現旋轉掃描效果_Android
- 2022-12-03 React中classnames庫使用示例_React
- 2022-06-04 C++求解二叉樹的下一個結點問題_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支