2017-06-19 99 views
0

我在尋找一種優雅的方式,以避免重新寫一個函數,它的實現幾乎是相同的,但只有簽名(輸入參數和數據類型的數量)是不同的。我知道函數重載在C中是不可能的。我也知道可變參數函數的存在。但我認爲他們在這種情況下不會有所幫助。替代函數重載用C

考慮下面的問題,在這裏我們需要計算一個三角形的面積。我們有兩個函數實現兩個不同的公式:S = 1/2bh和S = sqrt(s(s-a)(s-b)(s-c))。除計算面積外,每個功能還修改參數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); 

} 
+2

「避免代碼重複」和「功能重載」幾乎沒有任何關係。 –

+2

'無效area_tria1_nb(...,INT * NB,雙B,雙H,雙* S)'肯定這不是一個有效的原型。 –

+1

作爲一種模糊的評論...也許多態性可以讓你使用一個函數來執行你想要的各種行爲。 – byxor

回答

1

這我們可以利用使用數組的概念。

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',只需傳遞相應變量的地址即可。 這只是參考,可能並不完全適合您的情況。如有疑問,請再詢問一次。

+0

是的,這是我一直在想的一個選項:將所有參數傳遞給數據結構或參數數組。 – mabalenk

4

天真,簡單的方法來做到這一點:

#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中如何做功能重載。事實證明,這不一定是最好的方式。

一個更好的方法是使用一個結構參數來創建一個函數接口,該參數可以被調整以包含所有必要的參數。有了這樣的界面,您可以使用上述基於_Generic的簡單方法。類型安全和可維護。