Frage

Ja, ich verstehe den Unterschied zwischen Ihnen.Was ich wissen möchte ist:warum eine Methode ÜBERSCHREIBEN?Was das gute ist, es zu tun?Im Falle der überlastung:der einzige Vorteil ist, Sie haben nicht zu denken, dass verschiedene Bezeichnungen für Funktionen?

War es hilfreich?

Lösung

Overloading im Allgemeinen bedeutet, dass Sie zwei oder mehr Funktionen im gleichen Umfang mit dem gleichen Namen. Die Funktion, die besser passt die Argumente, wenn ein Anruf gewinnt gemacht und wird aufgerufen. Wichtig zu beachten, im Gegensatz zu einer virtuellen Funktion aufruft, ist, dass die Funktion, die bei der Kompilierung ausgewählt aufgerufen wird. Es hängt alles von dem statischen Typ des Arguments. Wenn Sie eine Überlastung für B und eine für D haben, und das Argument ist ein Verweis auf B, aber es deutet wirklich auf ein D Objekt, dann ist die Überlastung für B in C ++ gewählt wird. Das nennt man statische Dispatch im Gegensatz zu dynamische Dispatch . Sie überlasten, wenn Sie das gleiche wie eine andere Funktion mit dem gleichen Namen tun wollen, aber Sie wollen, dass für ein anderes Argument Typ zu tun. Beispiel:

void print(Foo const& f) {
    // print a foo
}

void print(Bar const& bar) {
    // print a bar
}

sie beide drucken ihr Argument, so dass sie überlastet sind. Aber der erste druckt eine foo, und die zweite druckt eine Bar. Wenn Sie zwei Funktionen haben, die verschiedene Dinge tun, es ist schlechter Stil, wenn sie den gleichen Namen haben, weil das zu Verwirrung darüber führen kann, was tatsächlich passiert, wenn die Funktionen aufrufen. Eine weitere usecase für Überlastung ist, wenn Sie zusätzliche Parameter für Funktionen haben, aber sie gerade nach vorne zu steuern, um anderen Funktionen:

void print(Foo & f, PrintAttributes b) { 
    /* ... */ 
}

void print(Foo & f, std::string const& header, bool printBold) {
    print(f, PrintAttributes(header, printBold));
}

Das kann für den Anrufer bequem sein, wenn die Optionen, die die Überlastung nehmen werden oft verwendet.

Übergeordnete ist etwas ganz anderes. Es konkurriert nicht mit Überlastung. Es bedeutet, dass, wenn Sie eine virtuelle Funktion in einer Basisklasse haben, können Sie eine Funktion mit der gleichen Signatur in der abgeleiteten Klasse schreiben können. Die Funktion in der abgeleiteten Klasse überschreibt die Funktion der Basis. Beispiel:

struct base {
    virtual void print() { cout << "base!"; }
}

struct derived: base {
    virtual void print() { cout << "derived!"; }
}

Nun, wenn Sie ein Objekt haben und die print Member-Funktion aufrufen, die Druckfunktion des abgeleitet wird immer dann aufgerufen, weil es die eine der Basis außer Kraft setzt. Wenn die Funktion print nicht virtuell war, dann ist die Funktion in der abgeleiteten würde die Basisfunktion nicht außer Kraft setzen, sondern nur verbergen es. Übergeordnete kann nützlich sein, wenn Sie eine Funktion haben, die eine Basisklasse übernimmt, und jeder, der daraus abgeleitet ist:

void doit(base &b) {
    // and sometimes, we want to print it
    b.print();
}

Nun, auch wenn bei der Kompilierung nur der Compiler weiß, dass b mindestens Base ist, Druck von der abgeleiteten Klasse aufgerufen. Das ist der Punkt der virtuellen Funktionen. Ohne sie würde die Druckfunktion der Basis genannt, und der in der abgeleiteten Klasse wäre es nicht außer Kraft setzen.

Andere Tipps

Dies wird einige mehr Klarheit Gedanken hinzufügen. eingeben Bild Beschreibung hier

Sie über Last Funktionen aus drei Gründen:

  1. Um zwei (oder mehr) Funktionen, die ähnlich ausführen, eng verwandte Dinge, die von den Typen differenziert und / oder die Anzahl der Argumente, die sie akzeptiert. Konstruiertes Beispiel:

    void Log(std::string msg); // logs a message to standard out
    void Log(std::string msg, std::ofstream); // logs a message to a file
    
  2. Um zwei (oder mehr) Möglichkeiten, um die gleiche Aktion auszuführen. Konstruiertes Beispiel:

    void Plot(Point pt); // plots a point at (pt.x, pt.y)
    void Plot(int x, int y); // plots a point at (x, y)
    
  3. , um die Fähigkeit bereitzustellen, die eine äquivalente Maßnahme angegeben zwei (oder mehr) verschiedene Eingangsarten auszuführen. Konstruiertes Beispiel:

    wchar_t      ToUnicode(char c);
    std::wstring ToUnicode(std::string s);
    

einige Fälle es lohnt sich argumentieren, dass eine Funktion von einem anderen Namen ist eine bessere Wahl als eine überladene Funktion. Im Fall der Konstrukteure ist Überlastung die einzige Wahl.


Über Reiten eine Funktion ist ganz anders, und dient einem ganz anderen Zweck. Funktion überwiegendes ist, wie Polymorphismus funktioniert in C ++. Sie überschreiben die Funktion, das Verhalten dieser Funktion in einer abgeleiteten Klasse zu ändern. Auf diese Weise stellt eine Basisklasse-Schnittstelle und die abgeleitete Klasse bietet Implementierung.

Aufschalten ist nützlich, wenn Sie von einer Basisklasse erben und wollen seine Funktionalität erweitern oder zu ändern. Selbst wenn das Objekt als Basisklasse umgewandelt wird, ruft sie Ihre überschriebene Funktion, die Basis nicht ein.

Überladen ist nicht notwendig, aber es sorgt dafür, dass das Leben leichter oder besser lesbar manchmal. Wohl kann es noch schlimmer machen, aber das ist, wenn sie nicht verwendet werden sollen. Zum Beispiel können Sie zwei Funktionen, die die gleiche Operation durchführen, sondern wirken auf verschiedene Arten von Dingen. Zum Beispiel sollte Divide(float, float) von Divide(int, int) unterschiedlich sein, aber sie sind im Grunde die gleiche Operation. Würden Sie nicht lieber einen Methodennamen erinnern, „Teile“, als merken „DivideFloat“, „DivideInt“, „DivideIntByFloat“, und so weiter?

Menschen, die bereits definiert sowohl das überladen und überschreiben, also werde ich nicht weiter darauf ein.

ASAFE fragte:

der einzige Vorteil [überlastung] ist Sie noch nicht, dass in einigen Bezeichnungen für Funktionen?

1.Sie nicht haben zu denken, mehrere Namen

Und das ist schon ein mächtiger Vorteil, nicht wahr?

Vergleichen wir mit bekannten C-API-Funktionen, und Ihre fiktive C++ Variante (N):

/* C */
double fabs(double d) ;
int abs(int i) ;

// C++ fictional variants
long double abs(long double d) ;
double abs(double d) ;
float abs(float f) ;
long abs(long i) ;
int abs(int i) ;

Dies bedeutet zwei Dinge:Ein, müssen Sie dem compiler den Typ der Daten, die Sie füttern Sie, um die Funktion durch Auswahl der richtigen Funktion.Zwei, wenn Sie wollen, es zu verlängern, müssen Sie Phantasie-Namen und die Benutzer Ihre Funktionen zu erinnern, die Recht ausgefallenen Namen.

Und alles, was er/Sie wollte, war zu haben, ist der absolute Wert einer numerischen variable...

Eine Aktion bedeutet, dass eine und nur eine function name.

Beachten Sie, dass Sie nicht beschränkt auf den Typ ändern eines Parameters.Alles kann sich ändern, solange es Sinn macht.

2.Für die Betreiber ist es zwingend

Mal sehen Betreiber:

// C++
Integer operator + (const Integer & lhs, const Integer & rhs) ;
Real operator + (const Real & lhs, const Real & rhs) ;
Matrix operator + (const Matrix & lhs, const Matrix & rhs) ;
Complex operator + (const Complex & lhs, const Complex & rhs) ;

void doSomething()
{
   Integer i0 = 5, i1 = 10 ;
   Integer i2 = i0 + i1 ; // i2 == 15

   Real r0 = 5.5, r1 = 10.3 ;
   Real r2 = r0 + r1 ; // r2 = 15.8

   Matrix m0(1, 2, 3, 4), m1(10, 20, 30, 40) ;
   Matrix m2 = m0 + m1 ; // m2 == (11, 22, 33, 44)

   Complex c0(1, 5), c1(10, 50) ;
   Complex c2 = c0 + c1 ; // c2 == (11, 55)
}

In dem obigen Beispiel, Sie tun wollen um zu vermeiden, mit nichts anderem als der + - operator.

Beachten Sie, dass C impliziten operator-überladung für built-in-Typen (inklusive C99 komplexer Typ):

/* C */
void doSomething(void)
{
   char c = 32 ;
   short s = 54 ;
   c + s ; /* == C++ operator + (char, short) */
   c + c ; /* == C++ operator + (char, char) */
}

Also auch in der nicht-Objekt-Sprachen, diese überlastung Sache verwendet wird.

3.Für Objekte, ist es zwingend notwendig

Lasst uns sehen die Verwendung eines Objekts grundlegende Methoden:Seine Konstruktoren:

class MyString
{
   public :
      MyString(char character) ;
      MyString(int number) ;
      MyString(const char * c_style_string) ;
      MyString(const MyString * mySring) ;
      // etc.
} ;

Einige könnten dies wie das überladen von Funktionen, aber in der Tat, es ist mehr ähnlich wie operator overloading:

void doSomething()
{
   MyString a('h') ;                  // a == "h" ;
   MyString b(25) ;                   // b == "25" ;
   MyString c("Hello World") ;        // c == "Hello World" ;
   MyString d(c) ;                    // d == "Hello World" ;
}

Fazit:Überlastung ist cool

In C, wenn Sie den Namen der Funktion, die Parameter sind implizit Teil der Signatur zu nennen.Wenn Sie "double fabs(double d)", dann, während die Signatur von fabs für den compiler ist die schmucklose "fabs", bedeutet es, dass Sie muss wissen, es dauert nur verdoppelt.

In C++, den Namen der Funktion nicht bedeutet, seine Unterschrift erzwungen.Seine Unterschrift bei Aufruf seines namens und seiner Parameter.Also, wenn Sie schreiben, abs(-24), kann der compiler wissen, was eine überlastung des abs muss es nennen, und Sie, wenn Sie zu schreiben, finden Sie mehr Natürliche:Sie möchten, dass der absolute Wert von -24.

Trotzdem, wer codiert etwas in irgendeiner Sprache mit dem Betreiber nutzt bereits überladen, werden Sie C oder Basic numerische Operatoren Java-string-Verkettung, C# - Delegaten, etc..Warum? denn es ist mehr Natürliche.

Und die Beispiele, die oben gezeigt wird, sind nur die Spitze des Eisbergs:Bei der Verwendung von Vorlagen, überladen geworden, sehr nützlich, aber das ist eine andere Geschichte.

Das Lehrbuchbeispiel ist die Klasse Tier mit Methode sprich (). Die Hundeunterklasse überschreibt () auf „Rinde“ sprechen, während die Katze Unterklasse überschreibt sprechen () auf „Miau“.

Eine Verwendung von Überlastung ist für die Verwendung in Vorlagen. In Vorlagen, schreiben Sie Code, der auf verschiedenen Datentypen verwendet werden kann, und nennen Sie es mit verschiedenen Arten. Wenn Funktionen, die unterschiedlichen Argumente hatten anders benannt werden, würde der Code für verschiedene Datentypen im Allgemeinen hat, anders zu sein, und Vorlagen einfach nicht funktionieren würden.

Während Sie keine Vorlagen noch schreiben können, die Sie verwenden fast sicher einige von ihnen. Ströme sind Vorlagen, und so sind Vektoren. Ohne eine Überlastung und somit ohne Vorlagen, müssen Sie Unicode-Streams aus ASCII-Streams, etwas anderes nennen, und Sie würden Arrays und Zeiger müssen anstelle von Vektoren verwendet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top