Vererbung



  • Hallo,

    warum erlauben viele Programmiersprachen nur , dass man von einer einzigen Klasse ableitet. C++ laesst ja auch beliebig oft ableiten... Welchen Nachteil koennte das haben ?



  • Man muss sich bspw. etwas zu https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem überlegen.

    Implementierungsvererbung ist heutzutage oft verpönt (siehe auch Composition vs. Inheritance) und für Interfacevererbung gibt es in den meisten Sprachen ohne "voller" Mehrfachvererbung zumindest Mehrfach-Interfacevererbung (bspw. Java, C#, ..).

    Wenn eine Klasse in mehr als zwei Vererbungshierarchien steckt widerspricht sie auch sehr oft dem Single-Responsibility-Principle.

    Sprich: für die ganz ganz wenigen Fälle wo man wirklich Mehrfachvererbung braucht wurde die Komplexität heutzutage oftmals als im Vergleich zu hoch bewertet und das Feature nicht in die Sprache mitaufgenommen.

    MfG SideWinder

    (C++ ist ja, imho, eins der besten Beispiele für eine Sprache mit viel zu vielen Features die kaum noch jemand vollumfassend verstehen kann)



  • Aso das Diamond Problem 🙂
    Aber eigentlich muesste man doch nur angeben , von welcher Klasse man die doppeldeutige Funktion aufrufen moechte. Hm...



  • Laut Robert C. Martin waren die Programmierer von Java wohl einfach nur zu faul/müde Mehrfachvererbung zu implementieren. Einen Grund gibt es nicht, außer viel Mythen und Meinungen.



  • Artchi schrieb:

    Laut Robert C. Martin waren die Programmierer von Java wohl einfach nur zu faul/müde Mehrfachvererbung zu implementieren. Einen Grund gibt es nicht, außer viel Mythen und Meinungen.

    Du meinst diesen Artikel?

    http://blog.cleancoder.com/uncle-bob/2015/01/08/InterfaceConsideredHarmful.html

    So why didn’t the authors of Java (and by extension C#) use one of the known solutions to implement multiple inheritance?

    I don’t know.
    I don’t know either, but I can guess.

    What’s your guess?
    Laziness.

    Laziness?
    Yeah, they didn’t want to deal with the issue. So they created a new feature that allowed them to sidestep it. That feature was the interface.

    Das ist natürlich eine völlig substanzlose Behauptung. Ich denke, er hat recht, daß die Grenze zwischen Interfaces und Klassen ursprünglich etwas willkürlich gezogen war (z.B.: warum sollten Interfaces keine Default-Methodenimplementierungen haben können?). Aber das Fehlen von C++-artiger Mehrfachvererbung mit "zu faul" zu erklären, finde ich umso verwerflicher, als er ja eigentlich sehr gut wissen dürfte, daß es nicht stimmt. Daß die Unterstützung von Mehrfachvererbung Kosten mit sich bringt (speziell für Laufzeit-Casts und Typechecks), die die Designer von Java und C# vermeiden wollten (weil abzusehen war, daß eine typsichere Sprache dauernd Laufzeit-Typchecks machen muß, was in Java mangels richtiger Generics bis heute der Fall ist). Der Verzicht auf MI ist ein Tradeoff. Außerdem ist es ja nicht so, daß MI nur dem Compilerbauer und dem Runtime-Implementierer zusätzliche Komplexität einbringt: der Benutzer muß sich plötzlich auch mit Problemen wie dem diamond und der Auflösung von Mehrdeutigkeiten bei geerbten Members beschäftigen. Ich denke, es hat nichts mit Faulheit zu tun, wenn ein Sprachdesigner entscheidet, den Nutzern seiner Sprache diese Problemklassen zu ersparen.

    Am schönsten finde ich, daß sein Beispiel Bullshit ist:

    OK, OK, but when do you really need multiple inheritance?
    So, here is what I would like to do:

    public class Subject {
    	private List<Observer> observers = new ArrayList<>();
    	private void register(Observer o) {
    		observers.add(o);
    	}
    	private void notify() {
    		for (Observer o : observers)
    		    o.update();
    	}
    }
    
    public class MyWidget {...}
    
    public class MyObservableWidget extends MyWidget, Subject {
    	...
    }
    

    Ah, that’s the Observer pattern!
    Yes. That’s the Observer pattern – done correctly.

    "Correctly"? Warum soll MyObservableWidget nur genau eine mögliche Notification unterstützen? Weil mehrfach von derselben Basisklasse erben geht ja auch mit MI nicht.

    Und es wird noch besser:

    Well then just implement the register and notify functions in MyObservableWidget
    What? And duplicate that code for every observed class? I don’t think so!

    Ist ja nicht so, als wäre das ein ungelöstes Problem:

    public class MyObservableWidget : MyWidget
    {
        public event EventHandler<MyNotifyArgs> Notify;
    }
    

    Und weiter:

    Well then have MyObservableWidget hold a reference to Subject and delegate to it?
    What? And duplicate the delegation code in every one of my observers? How crass. How degenerate. Ugh.

    Abgesehen davon, daß ich nicht verstehe, wieso es da im Observer mehr zu delegieren gäbe, ist auch dieses Pattern wohlbekannt und erprobt und hat den großen Vorteil der leichteren Kombinierbarkeit, cf. IObservable<> .



  • (Uncle Bob ist leider oftmals sehr dogmatisch und hält nicht viel von Untermauerung seiner Erfahrungswerte. Ansonsten schreibt er aber meistens ganz gute Blog Posts und wenn man den Kern seiner Bücher zwischen den Zeilen herauslesen kann auch ganz brauchbare Bücher.)

    MfG SideWinder


Anmelden zum Antworten