C++之函數重載

函數重載

函數重載構成條件

函數重載是C++允許在同一個作用域中聲明幾個名字相同功能相似的函數,函數重載常被用於處理功能類似、數據類型不同的問題。
高級語言在設計時就有一條原則,語言不能存在二義性,C++為了保證語言不存在二義性對函數重載進行約束:
要構成重載函數必須滿足以下幾個條件之一:

  1. 形參類型不同
  2. 形參個數不同
  3. 形參順序不同

通過程式碼實現一個重載函數,以下程式碼位於三個文件:
test.cpp

#include"func.h"


int main()
{
	f(1, 1.1);

	return 0;
}

func.h

#include<stdio.h>
#include<stdlib.h>

void f(int a, float b);
void f(float a, int b);

func.cpp

#include"func.h"

void f(int a, float b)
{
	printf("f(int a, float b)\n");
}

void f(float a, int b)
{
	printf("f(float a, int b)\n");
}

以上函數構成重載。上面函數構成重載滿足了函數形參順序不同的規則。運行結果為:
image-20220102142053935

從程式運行結果來看,我們不需要指定函數來運行,程式本身根據所傳實參類型來聯繫實際場景判斷用哪個函數,這種方式極大的方便程式設計師。

無法構成重載的特例

值得注意的是,函數的返回類型不同是無法構成函數重載的如:

void f(int a, float b)
{
	printf("f(1)\n");
}

int f(int a, float b)
{
	printf("f(2)\n");
}

還有無法構成重載的特例:

void f(a = 1)
{
    printf("f(a = 1)\n");
}

void f()
{
    printf("f()\n");
}

上面這種情況若是調用時有實參,編譯器可以判斷為有形參的函數執行,若無實參調用f();,由於上面函數有預設參數,編譯器無法判斷調用的是哪個函數,程式也就無法執行。
!!!注意 main函數無法重載!!!

不建議使用函數重載的場景

函數重載對於程式設計師使用起來確實方便,但在有些場景不建議使用函數重載。函數重載使用時最好應用於功能相似的函數。有些時候給函數起不同的名字有利於程式設計師理解函數的功能。舉個例子以下為幾個負責移動螢幕游標的函數:

void moveHome();
void moveAbs(int, int);
void moveRel(int, int, string direction);

將以上幾個函數名字起為move固然也可以,但是這幾個函數構成重載之後函數名就失去了本來擁有的資訊:

void move();
void move(int, int);
void move(int, int, string direction);

顯然第二個命名方式是不如第一個的。

C語言無法構成重載

在vs2019環境中將上面三個文件中的.cpp後綴全改為.c後綴,編譯程式後程式報錯

image-20220102162759548

由此可以看出C語言不支援函數重載。
那麼為什麼C語不支援函數重載而C++支援呢?

函數名字修飾

從程式碼到程式經過預處理,編譯,彙編,鏈接幾個過程,C++為了支援函數重載在編譯階段對函數名做了修飾,即名字修飾。由於Windows系統下名字修飾較為複雜,後面的名字修飾演示全為Linux系統下的演示。
在Linux系統下將test.cpp文件進行彙編後反彙編查看:

image-20220102173430008

image-20220102173534172

對比兩個函數修飾過的名字和諮詢大佬後知道Linux系統下函數名修飾規則:

_Z+函數名長度+函數名+形參類型
形參類型:
i int
f float
c char
pi *int
其它照此類推

由此可以看出,被以上的3個條件約束的函數重載時修飾後的名字是不會重複的,如此才能構成函數重載

C語言反彙編

我們可以通過此方法來看一下C語言的名字修飾情況,揭秘以下C語言為什麼不知此重載。
將一個f函數注釋掉後反彙編:

image-20220102192958741

可以看到,f函數是沒有經過任何修飾的。所以每個f函數名字都是一樣的,編譯器無法區分函數,所以無法構成重載。
Windows下反彙編的函數名字不太好看,但還是可以通過一些方法看到。

image-20220102193921311

如上圖,修飾過的函數名有些複雜,不利於分析,關於Windows下的函數名修飾規則可以在搜索引擎上看一下。