2015-07-15 8 views
5

Ich habe mich in letzter Zeit in Dlang versucht, weil C++ einfach nicht richtig saß, nachdem ich Python so lange benutzt hatte. Beim Herumturnen stieß ich auf das, was ich für eine sehr einfache Übung im Polymorphismus hielt. Ich nehme an, wie Sie erwarten, dass etwas funktioniert und was es tatsächlich tut, sind zwei völlig verschiedene Dinge, aus Gründen, die ein Endbenutzer wahrscheinlich nicht verstehen kann. Davon abgesehen, hier ist der Quellcode meiner „sandbox.D“:Warum ist der Aufruf der übergeordneten Methode dieser Unterklasse nicht polymorph?

import std.stdio; 

class Animal { 
    string voice = "--silence--"; 
    void speak() { 
     writeln(this.voice); 
    } 
} 

class Dog : Animal { 
    string voice = "Whoof!"; 
} 

int main() { 
    auto a = new Animal(); 
    auto d = new Dog(); 

    writeln(a.voice); // Prints "--silence--" 
    writeln(d.voice); // Prints "Whoof!" 

    a.speak(); // Prints "--silence--" 
    d.speak(); // Prints "--silence--" NOT "Whoof!" 

    return 0; 
} 

Ich denke, meine Frage ist, warum die „this“ Schlüsselwort einfach nicht zu sein scheint funktioniert, wie Sie es erwarten würde in die C++ - Nachfolgersprache.

Antwort

5

Methoden sind polymorph, Variablen nicht. Anstatt also die Stimme zu einer Variablen zu machen, willst du override speak im Kind haben.

Auch der Rückgabetyp auto funktioniert nicht mit Polymorphie, Sie müssen die Typen tatsächlich angeben. (Der Grund dafür ist, dass die automatische Rückgabe eine Funktionsvorlage im Compiler erstellt, die theoretisch mehrere überschreibbare Steckplätze in der Funktionstabelle haben könnte. Daher versucht sie einfach nicht, sie einzufügen.)

Probieren Sie es aus:

import std.stdio; 

class Animal { 
    void speak() { // changed to void instead of auto 
    writeln("--silence--"); 
    } 
} 

class Dog : Animal { 
    override void speak() { // the override tells it to override the base method 
    writeln("woof"); 
    } 
} 

int main() { 
    auto d = new Dog(); 
    d.speak(); 
    return 0; 
} 

Wenn Sie eine Menge gemeinsam genutzter Funktionalität haben und wollen eine Funktion mit geringfügigen Änderungen in untergeordneten Klassen wieder zu verwenden, können Sie eine Methode anstelle einer variablen machen, die nur etwas zurückgibt.

Wie string voice() { return "woof"; }, dann kann es in Kinder überschrieben werden.

+0

Ah, wie eine fristgerechte Antwort! Ich habe darüber debattiert, ob einige der "auto" -Schlüsselwörter entfernt werden sollen. Letztendlich habe ich es ohne Auto versucht und die richtigen Typen deklariert, aber es hat keinen Unterschied gemacht. Ich denke, dass objektorientierte Vererbung nicht ganz so nützlich ist, wie ich es mir vorgestellt habe :( –

+2

Es ist nützlich, ich muss nur daran denken, dass nur Methoden übersteuerbar sind, Variablen nicht. (Ich bin mir nicht sicher, ob es das gleiche ist Python, aber das funktioniert normalerweise in vielen OOP-Sprachen.) Obwohl die Vererbung ihre Grenzen hat, kann man viele Dinge damit lösen, aber es ist nicht immer der beste Weg. –

+0

Es ist sehr nützlich. Sie müssen nur verstehen, wie man es benutzt, und Sie haben missverstanden, wie es funktioniert hat. Sie müssen nur die Funktion anstelle der Member-Variable überschreiben, und es funktioniert gut. Die Codelänge ist nicht einmal viel anders. Und wenn Sie wollen Überschreibe stattdessen eine Membervariable, wickle sie einfach in eine Funktion, um ihren Wert zurückzugeben, und benutze die Funktion, anstatt die Variable direkt zu verwenden.Aber ich habe noch nie von einer Sprache gehört, die Variablen überladen hat, und wie Polymorphie unter der Haube funktioniert würde ziemlich viel bedeuten wrappi Sie sind sowieso in Funktionen unter der Haube. –

1

Ein anderer Weg ist Schablone diesen Parameter zu verwenden:

import std.stdio; 

class Animal { 
    string voice; 

    void speak(this C)() { 
     writeln((cast(C)this).voice); 
    } 
} 

class Dog : Animal { 
    string voice = "Whoof!"; 
} 

int main() { 
    auto a = new Animal(); 
    auto d = new Dog(); 

    a.speak(); // Prints "" 
    d.speak(); // Prints "Whoof!" 

    return 0; 
} 

Oder, wenn Sie nicht Stimme als Mitglied haben müssen: Ich schätze

import std.stdio; 

class Animal { 
    static immutable voice = ""; 

    void speak(this C)() { 
     writeln(C.voice); 
    } 
} 

class Dog : Animal { 
    static immutable voice = "Whoof!"; 
} 

int main() { 
    auto a = new Animal(); 
    auto d = new Dog(); 

    a.speak(); // Prints "" 
    d.speak(); // Prints "Whoof!" 

    return 0; 
} 
+0

Vielen Dank für die Antwort. Die Hauptlast meiner Verwirrung war nur, dass "dies" sich nicht auf die Stimme des Hundes bezog, sondern stattdessen auf die Stimme des Tieres. Ich denke, die Eigenschaften sind in Dlang nicht ganz so, wie ich dachte, sie wären :) –