首頁>Club>
7
回覆列表
  • 1 # 三袋大菠蘿

    派生的方法過載,最簡單就是函式指標。

    成員初始化讓函式指標指向不同實現函式即可。

    事實上,很多不喜歡C++的作者,釋出的開源庫都是基於函式指標實現多型特點的。

  • 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)

  • 中秋節和大豐收的關聯?
  • 你覺得有哪些值得推薦的美食?