2013-08-12 12 views
5

Ich versuche zu verstehen, wie die Vererbung in C# funktioniert. Ich schrieb den folgenden Code:In Bezug auf die Vererbung C#

class Program 
{ 
    static void Main(string[] args) 
    { 
     Animal animal = new Dog(); 
     animal.OverRideMe(); 
     //animal.NewMethod(); 
     Dog dog = (Dog)animal; 
     dog.OverRideMe(); 
     dog.NewMethod(); 
     Console.Read(); 
    } 
} 
public abstract class Animal 
{ 
    public Animal() 
    { 
     Console.WriteLine("Base Constructor"); 
    } 
    public virtual void OverRideMe() 
    { 
     Console.WriteLine("In Base Class's OverRideMe"); 
     Console.Read(); 
    } 
} 
public class Dog : Animal 
{ 
    public Dog() 
    { 
     Console.WriteLine("Derived Constructor"); 
    } 
    public override void OverRideMe() 
    { 
     Console.WriteLine("In Derived Class's OverRideMe"); 
     Console.Read(); 
    } 
    public void NewMethod() 
    { 
     Console.WriteLine("In Derived Class's NewMethod"); 
     Console.Read(); 
    } 
} 

Die CIL (Common Intermediate Language) Code für den Main() wie folgt aussieht:

.method private hidebysig static 
    void Main (
     string[] args 
    ) cil managed 
{ 
    // Method begins at RVA 0x2050 
    // Code size 42 (0x2a) 
    .maxstack 1 
    .entrypoint 
    .locals init (
     [0] class ConsoleApplication1.Animal animal, 
     [1] class ConsoleApplication1.Dog dog 
    ) 

    IL_0000: nop 
    IL_0001: newobj instance void ConsoleApplication1.Dog::.ctor() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: callvirt instance void ConsoleApplication1.Animal::OverRideMe() 
    IL_000d: nop 
    IL_000e: ldloc.0 
    IL_000f: castclass ConsoleApplication1.Dog 
    IL_0014: stloc.1 
    IL_0015: ldloc.1 
    IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe() 
    IL_001b: nop 
    IL_001c: ldloc.1 
    IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod() 
    IL_0022: nop 
    IL_0023: call int32 [mscorlib]System.Console::Read() 
    IL_0028: pop 
    IL_0029: ret 
} // end of method Program::Main 

Die Linien in CIL, die mich beunruhigen sind:

IL_000f: castclass ConsoleApplication1.Dog 
IL_0014: stloc.1 
IL_0015: ldloc.1 
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe() 
IL_001b: nop 
IL_001c: ldloc.1 
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod() 

nach dem castclass von Tiere zu Hund Typ des Codes wird ausgeführt dog.OverRideMe();. Dies wird CIL übersetzt als

IL_0016: callvirt Instanz ungültig ConsoleApplication1.Animal :: OverRideMe()

ich das Tier Objekt Hund Typ geworfen hatte. Warum sollte dog.OverRideMe(); in die obige Aussage in CIL übersetzt werden? Die Ausgabe des obigen Codes ist:

enter image description here

Dieser Ausgang hat nichts mit Basisklasse Tier aber CIL noch einen Anruf an, es zu tun.

+2

Ich verstehe nicht die Notwendigkeit, diese Frage zu verwerfen. Zumindest einen Kommentar abgeben, damit ich ihn verbessern kann. – msiyer

+1

Ihre Frage ist gut und ehrlich gesagt eine gute. Ignoriere die Hasser, sie sind auf der Seite dieser Tage IMO außer Kontrolle geraten. – jason

Antwort

4

Sie rufen eine virtuelle Methode auf. Der Aufruf der virtuellen Methode wird durch den Typ Laufzeit eines Objekts bestimmt. Sie können es ein Dog alles nennen, was Sie wollen, aber der Compiler wird weiterhin Anweisungen ausgeben, um die geeignete Methode zum Aufrufen von Laufzeit zu ermitteln. Beginnend mit der Kompilierungszeit Art von dog, geht es die Erbschaftskette hinauf, bis es die "oberste" Definition von OverRideMe findet und es einen virtuellen Methodenaufruf dafür abgibt. In diesem Fall ist die höchste Stelle in der Vererbungskette, die OverRideMe definiert ist, in Animal; Daher gibt es einen virtuellen Methodenaufruf für Animal.OverRideMe aus.

Hier ist eine previous answer, die Ihnen helfen könnte zu verstehen, was ein wenig besser geht.

: Die höchste Stelle in der Vererbungskette, in der die Methode definiert ist. Einige Vorsicht muss hier genommen werden, um zu verstehen, wie sich die Methode versteckt und was nicht.

+0

Sie müssen sich vielleicht das neue Schlüsselwort in der Methodensignatur ansehen. Dadurch wird die Methode beim tatsächlichen Typ nicht als Überschreibung aufgerufen. – Sebi

+1

@Sebi: Es gibt * nein * Schlüsselwort 'new', das verwendet wird, um irgendwelche Methoden im OP-Code zu verbergen. – jason

0

Es heißt "callvirt" - die virtuelle Tabelle ist mit "Tier" -Klasse verbunden, so dass der Anruf platziert werden sollte. Nach dem Auflösen der virtuellen Tabelle wird zur Laufzeit die beabsichtigte Methode aufgerufen.