C中函数重载的替代方法

时间:2017-06-19 13:25:38

标签: c overloading variadic-functions

我正在寻找一种优雅的方法来避免重写一个函数,它的实现几乎相同,但只有签名(输入参数的数量和它们的数据类型)是不同的。我知道在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 个答案:

答案 0 :(得分:5)

天真,简单的方法:

#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问题&#34;。您需要具有不同参数集的函数,并且您确信函数重载是解决它的最佳方法。因此,你问如何在C中进行函数重载。事实证明,这不一定是最好的方法。

更好的方法是使用单个struct参数创建一个函数接口,该参数可以适用于包含所有必需的参数。使用这样的界面,您可以使用基于_Generic的上述简单方法。输入安全且可维护。

答案 1 :(得分: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',只需传递相应变量的地址即可。 这只是参考,可能不适合您的情况。如果有任何疑问,请再次询问。