Ist es eine gute Idee, verschiedene Funktionssignaturen bereitzustellen, die dasselbe tun?

23

Hier ist eine C ++ - Klasse, die mit drei Werten erstellt wird.

class Foo{

    //Constructor
    Foo(std::string, int, char);

private:
    std::string foo;
    char bar;
    int baz;
};

Alle Parametertypen sind unterschiedlich.
Ich könnte den Konstruktor überladen, damit die Reihenfolge keine Rolle spielt.

class Foo{

    //Constructors
    Foo(std::string, char, int);
    Foo(std::string, int, char);
    Foo(char, int, std::string);
    Foo(char, std::string, int);
    Foo(int, std::string, char);
    Foo(int, char, std::string);


private:
    std::string foo;
    char bar;
    int baz;
};

Aber ist das eine gute Idee?
Ich habe damit angefangen, weil ich wusste, welche Dinge eine Klasse / Funktion benötigt;
Ich erinnerte mich nicht immer an die Reihenfolge, in der sie aufgenommen wurden.


Ich bin davon ausgegangen, dass der Compiler dies optimiert, als ob ich den gleichen Konstruktor aufgerufen hätte.

//compiler will implement this with the same code? 
//maybe not.. I could call a function to get a parameter, 
//and that function could change the state of the program, before calling
//a function to get another parameter and the compiler would have to
//implement both
Foo foo1("hello",1,'a');
Foo foo2('z',0,"world");

Was halten Sie davon, eine Funktion zu überladen, damit die Reihenfolge keine Rolle spielt?


Auch wenn ich einige Dienstprogramme schreibe,
ist es eine gute Idee, verschiedene Funktionsnamen anzugeben, die dasselbe tun?

z.B.

void Do_Foo();
void DoFoo();
void do_foo();
//etc..

Ich sehe diese beiden Konventionen nicht oft, aber ähnlich.
Soll ich die Gewohnheit abbrechen oder annehmen?

Trevor Hickey
quelle
1
Man sollte sich nur anstrengen, um mehrere Ausdrucksweisen bereitzustellen, wenn jede explizit bereitgestellte Möglichkeit in einigen Fällen einer der anderen klar und eindeutig überlegen ist. Das bedeutet nicht, dass man im Allgemeinen Anstrengungen unternehmen sollte, um sicherzustellen, dass etwas nur in einer kanonischen Form geschrieben werden kann, aber es ist nicht sinnvoll, Anstrengungen zu unternehmen, um zuzulassen, dass etwas auf eine Weise spezifiziert wird, die nicht die beste ist.
Supercat
Eine Art Duplikat meiner Frage hier (ich stimme jetzt zu, dass es eine schlechte Idee ist).
links

Antworten:

93

Ich könnte den Konstruktor überladen, damit die Reihenfolge [der Parameter] keine Rolle spielt ... Aber ist das eine gute Idee?

Nein.

Unterschiedliche Konstruktorüberladungen haben den gegenteiligen Effekt von dem, was Sie beabsichtigen. Der Programmierer, der nach Ihnen kommt, erwartet, dass verschiedene Überladungen ein unterschiedliches Verhalten aufweisen, und fragt: "Welche Art von unterschiedlichem Verhalten wird durch jede dieser Überladungen ausgedrückt?

Die meisten Programmierer erwarten, dass Methodenparameter in einer vordefinierten Reihenfolge vorliegen, und Tools wie IntelliSense geben ihnen die erwartete Reihenfolge der Parameter bei der Eingabe an.


Es ist das gleiche Problem, mehrere Funktionsnamen zu haben, die dasselbe tun. Programmierer erwarten von den Varianten ein unterschiedliches Verhalten. Bitte eine Funktion oder Methode pro Verhalten und nur ein konsistentes Benennungsmuster übernehmen.

Robert Harvey
quelle
14
viele positive Stimmen. Ich werde sofort aufhören. Danke dir.
Trevor Hickey
8
Außerdem können Sie Konstruktoren nicht anders benennen, um Ihren Zweck zu erläutern. Leser müssen dies aus den Parametern ableiten. Das Überladen des Konstruktors auf diese Weise erschwert das Verständnis.
Zachary Yates
3
"Mehrere Funktionsnamen haben, die dasselbe tun ..." - Schauen Sie sich für eine "gute" Zeit Rubys Klassen String Hash Array File an .
+1. Sie haben es mit Entwicklern / Programmierern zu tun. Microsoft Vorstellung von "Benutzer ist Affe", funktioniert hier nicht.
Manoj R
1
@ZacharyYates Das Fehlen von "Konstruktornamen" kann umgangen werden, indem stattdessen statische Konstruktionsmethoden verfügbar gemacht werden. Dies ist eine Standardpraxis in Java, wenn auch nicht so sehr in C ++.
Xion
14

Manchmal ist eine unterstützende Kommutierung zwischen Argumenten erforderlich. Zum Beispiel:

double operator *(int, double);
double operator *(double, int);

Wir wollen keine Multiplikation von intund double, um etwas anderes zu berechnen, wenn die Operanden umgekehrt sind. Wir wollen Programmierer auch nicht dazu zwingen, sich daran zu erinnern, wenn sie ints und multiplizieren doubles, das doublegeht links!

Es spielt keine Rolle, dass dies ein Operator ist, da das Gleiche gilt für:

footype plus(const footype &, const bartype &);
footype plus(const bartype &, const footype &);

Es kommt wirklich auf die Art der Funktion an. Während die meisten Programmierer wahrscheinlich Unterstützung für die Kommutativität in arithmetischen Bibliotheken wünschen, möchten sie nicht unbedingt, dass beispielsweise eine E / A-Bibliothek alle möglichen Argumentreihenfolgen unterstützt.

Die Sorge hängt wahrscheinlich von der erwarteten Verschachtelung ab, an der die Funktionsaufrufe beteiligt sein werden. Die Flexibilität der arithmetischen Operatoren ermöglicht es uns, die Gesamtstruktur des Syntaxbaums zu ändern, um den Gesamtausdruck zu verdeutlichen: Gruppieren Sie ähnliche Begriffe und dergleichen.

Kaz
quelle