2017-06-19 2 views
0

Ich suche eine elegante Möglichkeit, um das Umschreiben einer Funktion zu vermeiden, deren Implementierung fast gleich ist, aber nur die Signatur (die Anzahl der Eingangsparameter und deren Datentypen) ist unterschiedlich. Ich weiß, dass das Überladen von Funktionen in C nicht möglich ist. Ich weiß auch, dass variadische Funktionen existieren. Aber ich denke, dass sie in dieser Situation nicht hilfreich sein werden.Alternativen zum Funktionsüberladen in C

Betrachten Sie das folgende Problem, wo wir die Fläche eines Dreiecks berechnen müssen. Wir haben zwei Funktionen, die zwei verschiedene Formeln implementieren: S = 1/2bh und S = sqrt (s (s-a) (s-b) (s-c)). Abgesehen von der Berechnung des Bereichs ändert jede der Funktionen auch einen Parameter nb oder nthr. Schließlich gibt es eine Top-Level-Routine bisect_area_..., die eine Bisektionsprozedur für eine gegebene Funktion area_tria1 oder area_tria2 startet und sie für einen Parameter nb oder optimiert. Derzeit implementiere ich explizit zwei Bisektionsfunktionen: eine für die Signatur von area_tria1 und eine weitere für area_tria2. Ich denke, dass es eine bessere, elegantere Art geben muss, die eine einzige generische Halbierungsfunktion ermöglichen würde bisect_area_tria(). Bitte beachten Sie, dass die Eingabeparameter-Datentypen im realen Fall ebenfalls unterschiedlich sind.

Unten ist ein Skelett Pseudo-Code der Funktion Unterschriften:

// 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

"Vermeidung von Code-Duplizierung" und "Funktionsüberladung" haben wenig miteinander zu tun. –

+2

'void area_tria1_nb (..., int * nb, doppeltes b, doppeltes h, double * S)' sicher, dass dies kein gültiger Prototyp ist. –

+1

Als eine Art vager Kommentar ...Vielleicht erlaubt es Ihnen der Polymorphismus, eine einzige Funktion zu benutzen, um die etwas unterschiedlichen Verhaltensweisen auszuführen, die Sie wollen. – byxor

Antwort

1

Dieses wir nutzen können Array-Konzepte verwenden.

1) Übergeben alle Argumente (Werte), dh Doppelkonstanten als Arrays, wie dieser

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

gibt in dieser Funktion Gebrauch Array-Referenz wie folgt aus:

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]; 
} 

Für 'nb' oder 'nthr', übergeben Sie einfach die Adresse der entsprechenden Variable. Dies ist nur die Referenz, möglicherweise nicht genau für Ihre Situation. Wenn Zweifel bestehen, fragen Sie noch einmal.

+0

Ja, das ist eine Option, über die ich nachgedacht habe: Alle Argumente innerhalb einer Datenstruktur oder eines Arrays von Parametern übergeben. – mabalenk

4

Die naive, einfache Art und Weise, es zu tun:

#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'}); 
} 

Dieser Typ ist sicher, sondern unterstützt nur einen Parameter. Auf den ersten Blick scheint dies nicht ausreichend zu sein.

Wenn Sie völlig variable Parameterlisten möchten, dann müssten Sie eine Möglichkeit implementieren, variadic Makros zu analysieren und __VA_ARGS__. Wahrscheinlich ist es möglich. Wahrscheinlich ist es hässlich. Wahrscheinlich brauchen Sie das nicht.

Die Notwendigkeit einer Funktionsüberlastung im Allgemeinen könnte "ein XY-Problem" sein. Sie müssen Funktionen mit verschiedenen Parametersätzen haben und sind davon überzeugt, dass das Überladen von Funktionen der beste Weg ist, um sie zu lösen. Daher fragen Sie, wie man eine Funktionsüberladung in C durchführt. Das ist, wie sich herausstellt, nicht unbedingt der beste Weg.

Ein viel besserer Weg wäre, eine Funktionsschnittstelle mit einem einzigen Strukturparameter zu erstellen, der so angepasst werden kann, dass er alle notwendigen Parameter enthält. Mit einer solchen Schnittstelle können Sie die obige einfache Methode basierend auf _Generic verwenden. Geben Sie sicher und wartbar ein.