-
1 # 三袋大菠蘿
-
2 # 周林ZhouLin
這個問題描述其實有點問題,因為C++過載有兩種場景:
函式過載運算子過載問題本身沒有指明到底是哪種場景。現在就兩個場景分別給出答案。
如何用C語言實現C++函式過載?根據筆者的經驗,共有3種方法可以實現:
用C語言實現一個C++編譯器的對應子集, 後者自然可以支援過載;用函式指標加上void指標型別引數強制型別轉換,可以實現函式過載;用宏加上可變引數,可以實現函式過載如何用C語言實現C++運算子過載?運算子在C語言中是保留字, 無法透過普通變通方法實現過載。只能用C語言實現一個C++編譯器的對應子集, 後者自然可以支援過載。
用函式指標加上void指標型別引數強制型別轉換,實現函式過載用一個例子來說明:
typedef void (*funcOverride)(void *param);
void runFuncOverride(funcOverride f, void *param) {
f(param);
}
void func_with_int_param(void *iParam) {
int i = *(int *)iParam;
printf("int_param function is called, param is %d\n", i);
}
void func_with_char_param(void *cParam) {
char c = *(char *)cParam;
printf("char_param function is called, param is %c\n", c);
}
int i = 1;
char c="2";
runFuncOverride(func_with_int_param, &i);
runFuncOverride(func_with_char_param, &c);
輸出結果為:
bint_param function is called, param is 1
char_param function is called, param is 2
這種方法有一個明顯的劣勢:
需要呼叫方事先指定函式指標掛接的實際呼叫的函式實體,即便是用變通的方式——將型別資訊透過列舉型別或者字串型別作為引數傳遞,也無法完美消除這個劣勢。
根因是:執行時型別判斷並未收納於C語言標準規範中。
當然,一些C語言編譯器可能會提供內建函式來實現該特性,但畢竟不是標準,無法滿足跨平臺的需求。比方說gcc就提供了__builtin_types_compatible_p和typeof這兩個內建函式來做執行時型別判斷。
用宏加上可變引數,實現函式過載C語言支援可變引數,比方說prinf函式的原型如下:
int printf(const char *format, ...);
省略號表示引數為可變引數,而且C語言規定:省略號只能出現在函式形參的末尾,而且左邊必須有普通的形參。
需要注意的是:對於宏沒有上述限制。
C語言定義了一系列宏來完成可變引數函式引數的讀取和使用:宏va_start、va_arg和va_end。
在ANSI C標準下,這些宏定義在stdarg.h中:
void va_start(va_list ap, last);//取第一個可變引數;
type va_arg(va_list ap, type);//獲取當前位置引數值
void va_end(va_list ap);//將ap置為NULL
除此之外,還提供了一個非常有用的宏:__VA_ARGS__
這個宏直接引用可變引數列表。
有了上述前置知識,下面用一個例子來說明如何實現函式過載:
#define OneArgument(a) printf("One Argument func is called!\n")
#define TwoArguments(a, b) printf("Two Arguments func is called!\n")
#define MacroKernel(_1, _2, FUNC, ...) FUNC
#define Macro(...) MacroKernel(__VA_ARGS__, TwoArguments, OneArgument, ...)(__VA_ARGS__)
Macro(1);
Macro(2,3);
輸出結果為:
One Argument func is called!
Two Arguments func is called!
上述程式碼估計有些小夥伴看了有點暈,現在做要點說明:
Macro宏定義展開其實是:呼叫MacroKernel宏展開的函式實體,呼叫引數為可變引數,由Macro宏括號中的內容定義。__VA_ARGS__其實引用的就是Macro宏定義括號中的可變引數列表。MacroKernel宏定義中的_1,_2都是佔位符,沒有實際含義,作用是:保證在傳給Macro不同數目引數時,使得FUNC指向對應的函式實體:Macro引數數目為1時,FUNC指向OneArgument函式;引數數目為2時,FUNC指向TwoArguments函式。下面來看看實際的展開效果:
Macro(1)
=>MacroKernel(1, TwoArguments, OneArgument, ...)(1)
=>OneArgument(1)
Macro(2, 3)
=>MacroKernel(2, 3, TwoArguments, OneArgument, ...)(2, 3)
=>TwoArguments(2, 3)
回覆列表
派生的方法過載,最簡單就是函式指標。
成員初始化讓函式指標指向不同實現函式即可。
事實上,很多不喜歡C++的作者,釋出的開源庫都是基於函式指標實現多型特點的。