2010-06-01 20 views
25

Mam następujących klas:mylić o "ręcznym" kontra "nowa" w języku C#

class Base 
{ 
    public virtual void Print() 
    { 
     Console.WriteLine("Base"); 
    } 
} 

class Der1 : Base 
{ 
    public new virtual void Print() 
    { 
     Console.WriteLine("Der1"); 
    } 
} 

class Der2 : Der1 
{ 
    public override void Print() 
    { 
     Console.WriteLine("Der2"); 
    } 
} 

To jest mój główny sposób:

Base b = new Der2(); 
Der1 d1 = new Der2(); 
Der2 d2 = new Der2(); 

b.Print(); 
d1.Print(); 
d2.Print(); 

Wyjście jest Base, Der2, Der2.

O ile mi wiadomo, funkcja Override nie pozwoli na uruchomienie poprzedniej metody, nawet jeśli wskazuje na nią wskaźnik. Zatem pierwsza linia powinna również wyprowadzać Der2. Jednak wyszedł Base.

Jak to jest możliwe? Jak tam nie działało nadpisanie?

+0

Naprawdę Niesamowite przykład ... Jedyny podstęp tu jest: - intially, metoda BASE został ukryty metodą wirtualną "Der-1", więc metoda over-ride z „Der-2 "NIE MOŻNA wdrożyć. W ten sposób otrzymaliśmy wartość BASE. – Kings

Odpowiedz

27

Nigdy nie zmieniłeś wersji Base z . Ukryłeś to tylko z oddzielną wirtualną metodą (o tej samej nazwie) w Der1.

Podczas używania słowa kluczowego new na sygnaturze metody - mówisz kompilatorowi, że jest to metoda, która ma taką samą nazwę jak metoda jednej z twoich klas bazowych - ale nie ma żadnej innej relacji. Możesz uczynić tę nową metodę wirtualną (tak jak to robiłeś), ale to nie to samo, co przesłonięcie metody klasy bazowej.

W Der2 gdy zastępują Print jesteś rzeczywiście nadrzędnym „nowa” wersja, że ​​zadeklarowane w Der1 - nie jest to wersja Base. Eric Lippert ma excellent answer na nieco inne pytanie, które może pomóc ci zrozumieć, jak traktowane są metody wirtualne w języku C#.

W przykładzie, gdy dzwonisz Print, dzwonisz go w pierwszym przypadku poprzez odniesienie typu Base - tak ukryty (ale nie nadpisane) wersja Print nazywa. Pozostałe dwa wywołania są wysyłane do implementacji Der1, ponieważ w tym przypadku faktycznie przesłonięto metodę.

Możesz przeczytać więcej na ten temat w MSDN documentation of new and override.

Co może być przeznaczony do czynienia z Der1 (jak to było z Der2) jest użycie override kluczowe:

class Base 
{ 
    public virtual void Print() 
    { 
     Console.WriteLine("Base"); 
    } 
} 

class Der1 : Base 
{ 
    // omitting 'new' and using override here will override Base 
    public override void Print() 
    { 
     Console.WriteLine("Der1"); 
    } 
} 
+0

Tak właśnie zrobił z Der2. – GalacticCowboy

+0

@GalacticCowboy - rzeczywiście, o to mi chodziło. Prawdopodobnie to też było zamierzone w Der1, ale w jakiś sposób słowo kluczowe 'new' zostało wstawione, zamiast' override'. Zaktualizuję mój post, aby było to bardziej jasne. – LBushkin

+0

Dziękuję. Wspaniała odpowiedź, w pełni zrozumiałem, jak to działa teraz. – iTayb

5

To dlatego Der1 nie przesłanianiePrint, to zastępuje go zupełnie nowa metoda, która ma tę samą nazwę (jest to spowodowane użyciem słowa kluczowego new). Tak więc, gdy obiekt jest rzutowany na Base, wywołuje Print w Base; nie można przesłać połączenia

1

override zastąpi poprzednią metodę, ale jako klasa Der1 nie zastępują Print() (to Cienie go używać VB-ISM), a następnie najbardziej nadpisane Verion z Base „s Print() nazywa, co się dzieje być wersją, którą definiuje

0

Jak wszyscy mówili, klasa Der1 zastępuje Print() zamiast jej przesłonić. Aby zobaczyć to w akcji, możesz bazować d1 i d2 na Base, a następnie wywołać metodę drukowania. Następnie zwróci Base.

((Base)d2).Print(); //Base 
Powiązane problemy