簡體   English   中英

C函數重載的替代方法

[英]Alternatives to function overloading in C

我正在尋找一種避免重寫函數的優雅方法,該函數的實現幾乎相同,但是只有簽名(輸入參數及其數據類型的數量)不同。 我知道在C語言中不可能實現函數重載。我也知道可變參數函數的存在。 但是我認為他們在這種情況下不會有幫助。

考慮以下問題,我們需要在其中計算三角形的面積。 我們有兩個函數實現兩個不同的公式:S = 1 / 2bh和S = sqrt(s(sa)(sb)(sc))。 除了計算面積之外,每個函數還修改參數nbnthr 最后,有一個頂層例程bisect_area_...在給定函數area_tria1area_tria2上啟動二分程序,以針對參數nbnthr對其進行優化。 目前,我明確實現了兩個平分功能:一個用於area_tria1的簽名,另一個用於area_tria2的簽名。 我覺得必須有一個更好,更優雅的方法,該方法允許有一個通用的二等分函數bisect_area_tria() 請注意,實際上,我手邊的輸入參數數據類型也不同。

下面是函數簽名的基本偽代碼:

// Calculate area of triangle, modify and return parameter 'nb'
void area_tria1_nb(..., int *nb, double b, double h, double *S) {

    // change parameter 'nb'
    ...

    S = 0.5*b*h;
}

// Calculate area of triangle, modify and return parameter 'nthr'
void area_tria1_nthr(..., int *nthr, double b, double h, double *S) {

    // change parameter 'nthr'
    ...

    S = 0.5*b*h;
}

// Optimise calculation of area of triangle, for parameter 'nb' or 'nthr'
void bisect_area_tria1(..., double b, double h, double *S, int (*area_tria1)(double, double)) {
}

// Calculate area of triangle, modify and return parameter 'nb'
void area_tria2_nb(..., int *nb, double a, double b, double c, double *S) {

    // change parameter 'nb'
    ...

    S = sqrt(s*(s-a)*(s-b)*(s-c));
}


// Calculate area of triangle, modify and return parameter 'nthr'
void area_tria_2_nthr(..., int *nthr, double a, double b, double c, double *S) {

    // change parameter 'nthr'
    ...

    S = sqrt(s*(s-a)*(s-b)*(s-c));
}


// Optimise calculation of area of triangle, for parameter 'nb' or 'nthr'
void bisect_area_tria2(..., double a, double b, double c, double *S, int (*area_tria2)(double, double, double)) {
}

void main() {

    bisect_area_tria1(..., &nb,   b, h, &S, area_tria1_nb);
    bisect_area_tria1(..., &nthr, b, h, &S, area_tria1_nthr);

    bisect_area_tria2(..., &nb,   a, b, c, &S, area_tria2_nb);
    bisect_area_tria2(..., &nthr, a, b, c, &S, area_tria2_nthr);

}

天真的,簡單的方法:

#include <stdio.h>

void func_int (int x) { printf("%d\n", x); }
void func_char (char ch) { printf("%c\n", ch); }

#define func(param)          \
  _Generic((param),          \
    int:  func_int(param),   \
    char: func_char(param)); \

int main() 
{
  func(1);
  func((char){'A'});
}

這是類型安全的,但僅支持一個參數。 乍一看,這似乎不夠。

如果要使用完全可變的參數列表,則必須實現一種解析可變參數宏和__VA_ARGS__ 可能的話。 可能是丑陋的。 可能,這不是您所需要的。

通常,函數重載可能是“ XY問題”。 您需要具有帶有不同參數集的函數,並且確信函數重載是解決它的最佳方法。 因此,您會問如何在C中執行函數重載。事實證明,這不一定是最佳方法。

更好的方法是使用單個struct參數制作一個函數接口,該結構參數可以修改為包含所有必需的參數。 通過這樣的接口,您可以使用基於_Generic的上述簡單方法。 類型安全且可維護。

我們可以使用數組概念來利用這一點。

1)將所有參數(值)(即雙常量)作為數組傳遞,像這樣

double arr[]={a,b,c,h};
int trial_no; //1 or 2
bisect_area_tria2(..., &nthr,arr, &S, area_tria2_nthr,trial_no);

該函數中使用如下數組引用:

void area_tria2_nb(..., int *nb, double arr[], double *S,int trial_no) {

    // change parameter 'nb'
    ...
if(trial_no==2){
    S = sqrt(s*(s-arr[0])*(s-arr[1])*(s-arr[2]));
}
else
      S = 0.5*arr[1]*arr[3];
}

對於“ nb”或“ nthr”,只需傳遞相應變量的地址即可。 這只是參考,可能不適用於您的情況。 如有疑問,請再次詢問。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM