2012-05-05 11 views
6

Jestem programistą C# nowym w języku D. Jestem trochę zmieszany z OOP w języku programowania D.Dlaczego funkcja z chronionym modyfikatorem może zostać nadpisana i dostępna w każdym miejscu?

Zakładając, że mam następujące klasy:

public class A { 
    protected void foo() { 
     writefln("A.foo() called."); 
    } 
}; 

public class B : A { 
    public override void foo() { 
     writefln("B.foo() called."); 
    } 
}; 

protected modyfikator oznacza, że ​​można uzyskać dostęp do metody .foo() tylko na dziedziczonej klasy, więc dlaczego to D Program kompiluje normalnie?

Oto odpowiednik C# .NET:

using System; 

public class A { 
    protected virtual void foo() { 
     Console.WriteLine("a.foo() called."); 
    } 
}; 

public class B : A { 
    public override void foo() { 
     Console.WriteLine("b.foo() called."); 
    } 
}; 

public class MainClass { 
    public static void Main(string[] args) { 
     A a = new A(); 
     B b = new B();  
     a.foo(); 
     b.foo(); 
    } 
}; 

To nie kompiluje i biorąc pod uwagę następujący komunikat o błędzie (zgodnie z oczekiwaniami):

test.cs (10 , 30): error CS0507: B.foo()': cannot change access modifiers when overriding chronione 'odziedziczone członkiem `A.foo()'

Może ktoś wyjaśnić to zachowanie D? Z góry dziękuję.

+2

Dlaczego jesteś zdezorientowany? C# i D są po prostu różnymi językami, więc robią różne rzeczy. Na pierwszy rzut oka oba podejścia mają dla mnie jakiś sens, więc to projektanci języka decydują, którą drogę wybrać. – svick

+0

Humm, ponieważ miałem na myśli to, że modyfikatory dostępu obiektowego języka programowania działały w ten sam sposób. – Jack

+0

downvotes- potrafisz wyjaśnić? – Jack

Odpowiedz

16

Nie ma sensu zapobiegać przesłonięciu. Klasa pochodna może implementować trywialną funkcję przekazywania, która umożliwia dostęp. Rozważmy:

public class A { 
    protected void foo() { 
     writefln("A.foo() called."); 
    } 
}; 

public class B : A { 
    protected override void foo() { // OK 
     writefln("B.foo() called."); 
    } 
    public void call_foo() { 
     foo(); // But I allowed public access anyway! 
    } 
}; 

Tak więc, mimo że nie przedefiniować poziom dostępu foo, nadal wolno publiczny dostęp do niego i nic nie można na to poradzić. Umożliwienie redefinicji jest prostsze.

+0

Humm, to jest projektantka 'D'. W języku 'C# .NET' nie jest możliwe napisanie czegoś takiego jak metoda' call_foo() '. Dano mu "błąd CS0122: A.foo()" jest niedostępne ze względu na poziom ochrony. "Dziękuję za odpowiedź. :) – Jack

+0

@Jack: Co, w języku C# nie można napisać publicznej metody, która wywołuje metodę chronioną? – Puppy

+0

Nie. Nie działa dla mnie, testowałem na C# -Mono i otrzymałem powyższy komunikat o błędzie. – Jack

5

Zachowanie D w tym przypadku odpowiada zachowaniu Javy. Klasa pochodna może nadawać swojej funkcji poziom dostępu, który jest mniej restrykcyjny niż ten na funkcji w klasie bazowej, ale nie taki, który jest bardziej restrykcyjny. Tak, protected funkcja może być zmieniona albo jako protected lub public, ale to nie może być pominięte jako private i public funkcja może być zmieniona jedynie jako public.

Nie mam pojęcia, dlaczego C# ograniczyłoby wartość protected, tak że nie można jej zastąpić funkcją public. Jako ktoś, kto zaprogramował dużo w C++, D i Javie, ale bardzo mało w C#, wybór C# tutaj ma dla mnie bardzo mały sens. C++, D i Java wszystko na to pozwalają.

7

Ponieważ istnieje kilka świetnych odpowiedzi na pytanie "dlaczego to możliwe?" Myślę, że C# zasługuje na wyjaśnienie, dlaczego nie jest to możliwe: chodzi o "filozofię" projektowania języka i można sprowadzić ją do "jest-a" kontra "ma-a" zderzenie pomysłów.

C++ to myślenie "ma-a", część z nich została przekazana do D i Java. B ma metoda foo i jest to najważniejsze zarówno dla kompilatora, jak i programisty, a nie B. W C++ możliwe jest nawet ponowne wykreślenie metody jako prywatnej (lub dziedziczenie klasy jako prywatnej), co oznacza, że ​​członek A NIE będzie wystawiony na działanie przez B.

C# jest hardcorowy w stosunku do koncepcji "is-a". Dlatego, ponieważ tutaj B faktycznie jest A, wszystko w B musi być dokładnie jak w A. Ani kompilator, ani programista nie muszą się martwić o zmiany, ponieważ żadne zmiany nie są możliwe.B zawsze jest idealnym zamiennikiem dla A.

Filozofia "is-a" zabrania programu C# publikowania wcześniej chronionego członka, nawet jeśli jest to banalne, gdy robi się to za pomocą publicznego opakowania. Ma to niewielki sens i jest tylko niewielką niedogodnością - ale to bardzo ważne, aby zachować spójność filozofii językowej.

Powiązane problemy