1. 程式人生 > 實用技巧 >C++____函式過載

C++____函式過載

函式過載

實現函式過載的條件

同一個作用域

引數個數不同

引數型別不同

引數順序不同

//例子
//1. 函式過載條件
namespace A{
void MyFunc(){ cout << "無引數!" << endl; }
void MyFunc(int a){ cout << "a: " << a << endl; }
void MyFunc(string b){ cout << "b: " << b << endl; }
void MyFunc(int a, string b){ cout << "a: " << a << " b:" << b << endl;}
void MyFunc(string b, int a){cout << "a: " << a << " b:" << b << endl;}
}
//2.返回值不作為函式過載依據
namespace B{
void MyFunc(string b, int a){}
//int MyFunc(string b, int a){} //無法過載僅按返回值區分的函式
}

注意點:

函式過載要防備二義性:

void MyFunc(string b){
cout << "b: " << b << endl;
}
//函式過載碰上預設引數
void MyFunc(string b, int a = 10){
cout << "a: " << a << " b:" << b << endl;
}
int main(){
MyFunc("hello"); //這時,兩個函式都能匹配呼叫,產生二義性
return 0;
}

函式過載不能用返回值作為過載條件

函式過載實現原理

編譯器為了實現函式過載,也是預設為我們做了一些幕後的工作,編譯器用不同的引數型別來修飾不同的函式名,比如void func(); 編譯器可能會將函式名修飾成func,當編譯器碰到void func(int x),編譯器可能將函式名修飾為func_int,當編譯器碰到void func(int x,char c),編譯器可能會將函式名修飾為_func_int_char我這裡使用”可能”這個字眼是因為編譯器如何修飾過載的函式名稱並沒有一個統一的標準,所以不同的編譯器可能會產生不同的內部名。

void func(){}
void func(int x){}
void func(int x,char y){}

以上三個函式在linux下生成的編譯之後的函式名為:

_Z4funcv //v 代表void,無引數
_Z4funci //i 代表引數為int型別
_Z4funcic //i 代表第一個引數為int型別,第二個引數為char型別

在C++中呼叫c語言的函式

方法1:新增extern "c"

extern "C"的主要作用就是用來在C++中呼叫c語言的程式碼

由於c++中需要支援函式過載,所以c和c++中對同一個函式經過編譯後生成的函式名是不相同的,這就導致了一個問題,如果在c++中呼叫一個使用c語言編寫模組中的某個函式,那麼c++是根據c++的名稱修飾方式來查詢並連結這個函式,那麼就會發生連結錯誤。例如,c++中呼叫MyFunc函式,在連結階段會去找Z6Myfuncv,結果是沒有找到的,因為這個MyFunc函式是c語言編寫的,生成的符號是MyFunc。

那麼如果我想在c++呼叫c的函式怎麼辦?

extern "C"的主要作用就是為了實現c++程式碼能夠呼叫其他c語言程式碼。加上extern "C"後,這部分程式碼編譯器按c語言的方式進行編譯連結,而不是按c++的方式。

//例如
extern "c" void show();

方法2:來處理多個函式

在c語言對應的函式的標頭檔案裡面新增巨集來處理:

#ifndef MYMODULE_H
#define MYMODULE_H

#include<stdio.h>


//從這裡開始
#if __cplusplus
extern "C"{
#endif

void func1();
int func2(int a,int b);

#if __cplusplus
}
#endif //新增這一坨就好,在這裡結尾

#endif

對於.c的實現標頭檔案中的函式就正常實現就好了

同樣在呼叫的cpp中這樣用也是一樣的