2009-03-06 11 views
13

Weźmy przykład w C#Konstruktorzy i dziedziczenie

public class Foo 
{ 
    public Foo() { } 
    public Foo(int j) { } 
} 

public class Bar : Foo 
{ 

} 

Teraz wszystkie publiczne członkowie Foo jest dostępny w barze z wyjątkiem konstruktora. nie mogę zrobić coś takiego

Bar bb = new Bar(1); 

Dlaczego konstruktorzy nie są dziedziczne?

UPDATE

rozumiem możemy konstruktorów łańcuchowe, ale chciałbym wiedzieć, dlaczego powyższy konstrukt jest nieprawidłowy. Jestem pewien, że powinien istnieć ku temu ważny powód.

+0

duplikat http://stackoverflow.com/questions/426484/why-are-constructors-nie-inited –

Odpowiedz

14

Konstruktory nie są dziedziczne, ponieważ mogą powodować dziwne i niezamierzone zachowanie. Bardziej szczegółowo, jeśli dodałeś nowy konstruktor do klasy bazowej, wszystkie klasy pochodne pobierają instancję tego konstruktora. W niektórych przypadkach jest to złe, ponieważ może twoja klasa bazowa określa parametry, które nie mają sensu dla twoich klas pochodnych.

Powszechnie podawanym przykładem jest to, że w wielu językach klasa bazowa dla wszystkich obiektów (potocznie zwana "Obiektem") ma konstruktor bez parametrów. Jeśli konstruktory zostałyby odziedziczone, oznaczałoby to, że wszystkie obiekty mają konstruktor bez parametrów i nie ma sposobu, aby powiedzieć: "Chcę, aby ludzie, którzy tworzą instancję tej klasy, dostarczali parametry X, Y i Z, w przeciwnym razie ich kod nie powinien się kompilować. " Dla wielu klas ważne jest, aby określone parametry były właściwe dla ich prawidłowego funkcjonowania, a uczynienie konstruktorów nie-dziedzicznymi jest częścią sposobu, w jaki autorzy klas mogą zagwarantować, że niektóre parametry są zawsze zdefiniowane.

Edytuj, aby odpowiadać na komentarze: Ramesh wskazuje, że jeśli konstruktory zostałyby odziedziczone tak, jak chciałby, to zawsze mógłby przesłonić konstruktory klasy bazowej używając prywatnych konstruktorów deklarowanych w każdej klasie pochodnej. Jest to z pewnością prawda, ale jest to problem logistyczny związany z tą strategią. Wymaga to, aby piszący klas pochodnych uważnie obserwowali klasy bazowe i dodawali prywatnego konstruktora, jeśli chcą blokować dziedziczenie konstruktora klasy podstawowej. Nie tylko jest to dużo pracy dla osób piszących klasy pochodne, ten rodzaj ukrytej zależności między klasami jest dokładnie taki, który może powodować dziwne zachowanie.

Ramesh - nie jest tak, że to, co opisałeś byłoby niemożliwe do dodania do języka. Zasadniczo nie jest to robione, ponieważ takie zachowanie może wprowadzać w błąd ludzi i prowadzić do wielu dodatkowych debugowania i pisania kodu.

Quintin Robinson zapewnia kilka bardzo wartościowych odpowiedzi na to pytanie w komentarzach, które zdecydowanie warto przeczytać.

+0

Jeśli dodasz konstruktora do klasy bazowej, będzie można zainicjować rzeczy obecny tylko w tej klasie i to jest dobre zachowanie, nie widzę powodu, dla którego mówisz, że jest to złe. – Ramesh

+0

Ponieważ możesz * wymagać * niezasadowych członków do zainicjowania w twojej klasie pochodnej. –

+0

@Simon - Jeśli tak, zawsze mogę przesłonić moich konstruktorów, takich jak funkcje – Ramesh

7

Są (przez łańcuchowym), trzeba by łańcuchu konstruktora w obiekcie pochodzącego .. IE:

public class Foo 
{ 
    public Foo() { } 
    public Foo(int j) { } 
} 

public class Bar : Foo 
{ 
    public Bar() : base() { } 
    public Bar(int j) : base(j) { } 
} 

Konstruktorzy w obiektach pochodzących wtedy łańcuch wołania zrobić konstruktorów w bazie obiekty.

This article podaje kilka dodatkowych przykładów, jeśli chcesz przeczytać dalej.

+0

Rozumiem, że łańcuchy, ale dlaczego mój przykład jest nieprawidłowy, to co chciałbym zrozumieć (mam zaktualizowałem pytanie, żeby podkreślić to samo) – Ramesh

+0

Rozumiem, przepraszam za odpowiedź na pytanie, o które mnie nie zapytałeś. Myślę, że przeczytałem trochę za daleko. –

+0

Dzięki Quintin, twoje pytania sprawiły, że pomyślałem. +1 za jedną z odpowiedzi na inne pytanie. – Ramesh

0

myślę, że można wykonać następujące czynności:

public class Bar : Foo 
{ 
    public Bar (int i) 
    : base (i) 
    { 
    } 
} 

mogę być trochę off - ale ogólna idea.

+0

Rozumiem, że łańcuchy, ale dlaczego mój przykład jest nieprawidłowy jest to, co chciałbym zrozumieć (zaktualizowałem pytanie, aby podkreślić to samo) – Ramesh

1

Konstruktory nie są dziedziczone ze względów projektowych. (Zauważ, że jest to ta sama sytuacja w każdym języku obiektowym, o którym wiem.) Prosta odpowiedź jest taka, że ​​w wielu przypadkach naprawdę nie chciałbyś mieć tych samych konstruktorów, co klasa podstawowa, która jest dostępna. Zobacz this SO thread po więcej pełnych wyjaśnień.

0

Prosta odpowiedź brzmi, że język nie działa w ten sposób.

Prawdziwym pytaniem, o które prosisz, jest to, dlaczego nie działa w ten sposób :-) Cóż, jest to arbitralny wybór, a wynika to z C++ i Java (i prawdopodobnie wielu innych języków, które wpłynęły na C#) .

Prawdopodobną przyczyną jest to, że kompilator wygeneruje tylko konstruktor, który nie przyjmuje żadnych argumentów i po prostu wywołuje funkcję rodzica, jeśli chcesz uzyskać więcej niż to, co kompilator robi samemu. Jest to najlepszy wybór, ponieważ szanse na to, co robisz, są większe niż wsparcie dla konstruktora macierzystego.

2

Jednym z powodów, dla których można wprowadzić konstruktor do klasy, jest to, że nie ma sensu mieć instancji tej klasy bez określonej "zależności". Na przykład może to być klasa dostępu do danych, które musi mieć połączenie z bazą danych:

public class FooRepository 
{ 
    public FooRepository(IDbConnection connection) { ... } 
} 

Jeśli wszyscy konstruktorzy publicznych z klas bazowych były dostępne, a następnie użytkownik klasy repozytorium byłby w stanie używać domyślnego konstruktora System.Object do tworzenia nieprawidłową instancję klasy:

var badRepository = new FooRepository(); 

Ukrywanie dziedziczonych konstruktorów domyślnie oznacza, że ​​można wymusić zależności bez martwienia się o użytkowników tworzących „nieważny” instancje.

+0

+1 - Rozumiem, że metody nie muszą się ukrywać, ale konstruktor musi być z powodów intializacji. – Ramesh

1

Niektóre dyskusje

Podstawowym założeniem jest to, aby dostarczyć jak najwięcej kontrolę twórcy jak to możliwe. I możesz mieć prywatne bazy. Jak wtedy stworzyłeś obiekt?

2

Konstruktor Foo może tylko wiedzieć, jak zainicjować obiektu Foo, więc nie ma sensu, że powinien również wiedzieć, jak zainicjować potencjalnego podklasę

public class Bar : Foo 
{ 
public Bar(int i) : base(i) { } 
} 

historię konstruktor mówi to: „Hej podstawa klasę proszę robić, co trzeba zrobić, aby być w dobrym stanie, abym mógł iść dalej i odpowiednio się przygotować ".

2

Załóżmy, że konstruktorzy byli dziedziczni. W jaki sposób wyłączyć konstruktory dziedziczone w wielu przypadkach, gdyby nie miały one sensu dla podklasy?

Zamiast komplikować język za pomocą mechanizmu blokowania dziedziczenia, projektanci języka optowali za tym, aby konstruktory nie były dziedziczne.

+0

+1 - Jedna z dokładnych odpowiedzi – Ramesh

+0

Co powiedzie się na zapewnienie, że jeśli podklasa zawiera jakiekolwiek konstruktory, wówczas żaden konstruktor macierzysty nie jest "dziedziczony", ale poza tym wszystkie są (co oznacza, że ​​konstruktory byłyby automatycznie generowane w celu połączenia z konstruktorami macierzystymi z dopasowaniem podpisy)? Każda klasa, która nie chce "dziedziczyć" wszystkich swoich konstruktorów rodzica, powinna dostarczyć przynajmniej jedną z jego własnych. Jeśli rodzic nie ma konstruktora bez parametrów, nie byłoby innego znaczenia logicznego dla klasy bez konstruktorów. – supercat

0

Naprawdę, ponieważ konstruktor nadrzędny nie w pełni zainicjował obiekt potomny.Konstruktor jest czymś osobistym pod tym względem. Dlatego większość języków nie dziedziczy konstruktorów.