14 Stimmen

Konstrukteure und Vererbung

Nehmen wir ein Beispiel in C#

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

public class Bar : Foo
{

}

Nun sind alle öffentlichen Mitglieder von Foo in Bar zugänglich, außer dem Konstruktor. Ich kann nicht etwas tun wie

Bar bb = new Bar(1);

Warum sind die Konstruktoren nicht vererbbar?

UPDATE

Ich verstehe, dass wir Konstruktoren verketten können, aber ich würde gerne wissen, warum das obige Konstrukt nicht gültig ist. Ich bin sicher, dass es dafür einen triftigen Grund gibt.

16voto

James Thompson Punkte 44724

Konstruktoren sind nicht vererbbar, da dies zu einem seltsamen und unbeabsichtigten Verhalten führen könnte. Genauer gesagt, wenn Sie einen neuen Konstruktor zu einer Basisklasse hinzufügen, erhalten alle abgeleiteten Klassen eine Instanz dieses Konstruktors. Das ist in manchen Fällen schlecht, weil Ihre Basisklasse vielleicht Parameter angibt, die für Ihre abgeleiteten Klassen nicht sinnvoll sind.

Ein häufig genanntes Beispiel dafür ist, dass in vielen Sprachen die Basisklasse für alle Objekte (allgemein als "Objekt" bezeichnet) einen Konstruktor ohne Parameter hat. Wenn Konstruktoren vererbt würden, würde das bedeuten, dass alle Objekte einen parameterlosen Konstruktor haben, und es gibt keine Möglichkeit zu sagen: "Ich möchte, dass Leute, die eine Instanz dieser Klasse erstellen, die Parameter X, Y und Z angeben, sonst sollte ihr Code nicht kompiliert werden." Für viele Klassen ist es wichtig, dass bestimmte Parameter für ihre korrekte Funktion definiert sind, und Konstruktoren nicht vererbbar zu machen ist ein Teil der Art und Weise, wie Klassenautoren garantieren können, dass einige Parameter immer definiert sind.

Bearbeiten, um auf Kommentare zu reagieren: Ramesh weist darauf hin, dass, wenn Konstruktoren vererbt würden, wie er es gerne hätte, er die Konstruktoren der Basisklasse immer durch privat deklarierte Konstruktoren in jeder abgeleiteten Klasse überschreiben könnte. Das ist sicherlich richtig, aber es gibt ein logistisches Problem mit dieser Strategie. Sie erfordert, dass die Verfasser abgeleiteter Klassen die Basisklassen genau beobachten und einen privaten Konstruktor hinzufügen müssen, wenn sie die Vererbung des Konstruktors der Basisklasse blockieren wollen. Dies bedeutet nicht nur eine Menge Arbeit für die Verfasser abgeleiteter Klassen, sondern diese Art der impliziten Abhängigkeit zwischen den Klassen ist genau die Art von Dingen, die zu seltsamem Verhalten führen kann.

Ramesh - es ist nicht so, dass es unmöglich wäre, das, was Sie beschreiben, zu einer Sprache hinzuzufügen. Im Allgemeinen wird es nicht gemacht, weil diese Art von Verhalten die Leute verwirren und zu einer Menge zusätzlicher Fehlersuche und Code-Schreiben führen könnte.

Quintin Robinson gibt in den Kommentaren einige sehr interessante Antworten auf diese Frage, die es auf jeden Fall zu lesen lohnt.

8voto

Quintin Robinson Punkte 78652

Sie sind (durch Verkettung), müssten Sie den Konstruktor in Ihrem abgeleiteten Objekt verketten. IE:

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

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

Die Konstruktoren in den abgeleiteten Objekten werden dann die Aufrufe der Konstruktoren in den Basisobjekten verketten.

Dieser Artikel finden Sie weitere Beispiele, wenn Sie mehr lesen möchten.

2voto

Matt Hamilton Punkte 193704

Ein Grund, warum man einen Konstruktor in eine Klasse einführen kann, ist, dass es keinen Sinn macht, eine Instanz dieser Klasse ohne eine bestimmte "Abhängigkeit" zu haben. Es könnte sich zum Beispiel um eine Datenzugriffsklasse handeln, die eine Verbindung zu einer Datenbank haben muss:

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

Wenn alle öffentlichen Konstruktoren von Basisklassen verfügbar wären, könnte ein Benutzer Ihrer Repository-Klasse den Standardkonstruktor von System.Object verwenden, um eine ungültige Instanz Ihrer Klasse zu erzeugen:

var badRepository = new FooRepository();

Das standardmäßige Ausblenden vererbter Konstruktoren bedeutet, dass Sie Abhängigkeiten erzwingen können, ohne sich Sorgen machen zu müssen, dass Benutzer "ungültige" Instanzen erstellen.

2voto

ecoffey Punkte 3173

El Foo Konstruktor kann nur wissen, wie man ein Foo-Objekt initialisiert, also macht es keinen Sinn, dass er auch weiß, wie man eine mögliche Unterklasse initialisiert

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

Die Geschichte, die der Konstrukteur erzählt, lautet: "Hey, Basisklasse, bitte tu alles, was du tun musst, um in einem guten Zustand zu sein, damit ich loslegen und mich richtig einrichten kann.

2voto

Wim Coenen Punkte 64891

Angenommen, Konstruktoren wären vererbbar. Wie würden Sie die vererbten Konstruktoren in den vielen Fällen deaktivieren, in denen sie für eine Unterklasse nicht sinnvoll sind?

Anstatt die Sprache mit einem Mechanismus zum Blockieren der Vererbung zu verkomplizieren, haben sich die Sprachdesigner dafür entschieden, Konstruktoren einfach nicht vererbbar zu machen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X