2013-06-01 13 views
7

Ludzie mówią, że dziedziczenie C++ jest złe, więc Java "naprawiła" ten problem za pomocą interfejsu.Czy Scala mixin jest naprawdę lepszy od wielokrotnego dziedziczenia C++?

Ale Scala wprowadziła trait s, czy są ... interfejsem z częściową implementacją? Czy to nie przywróciło wielu dziedziczeń?

Czy to oznacza, że ​​ludzie z Scali uważają, że dziedziczenie jest dobre? Czy mają jakieś krytyczne różnice, których nie zauważyłem?

+6

Proszę spojrzeć na książkę [Programowanie w Scali] (http://www.artima.com/pins1ed/traits.html#12.6), strona 258, § 12.6. Uważam, że to wyjaśnienie jest bardzo dobre i może próbować przeformułować je, ale nie chciałbym - trudno napisać coś bardziej kompleksowego. W skrócie, w Scali nie ma tak zwanego [* diamond problem *] (https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem) (który istnieje w C++ i dlatego tak wiele dziedziczenia C++ było tak mocno krytykowane) , z powodu braku konstruktorów, dobrze zdefiniowanej kolejności wywoływania metod i innego pojęcia * super *. –

Odpowiedz

8

Najgorszą częścią dziedziczenia wielokrotnego jest dziedziczenie diamentów, gdzie podklasa ma dwie lub więcej ścieżek do tego samego rodzica w dowolnym miejscu łańcucha. Powoduje to niejednoznaczność, jeśli implementacje różnią się wzdłuż dwóch ścieżek (to znaczy są nadpisywane względem pierwotnej implementacji). W C++ rozwiązanie jest szczególnie brzydkie: osadzasz obie niekompatybilne klasy nadrzędne i musisz określić, kiedy wywołasz wybraną implementację. Jest to mylące, tworzy dodatkową pracę na każdej stronie wywołania (lub, co bardziej prawdopodobne, wymusza jawne nadpisanie i określa to, co chcesz, ta praca ręczna jest nużąca i stwarza szansę na błąd) i może prowadzić do tego, że obiekty są większe niż powinni być.

Scala rozwiązuje niektóre, ale nie wszystkie problemy, ograniczając dziedziczenie wielokrotne do cech. Ponieważ cechy nie mają konstruktorów, ostateczna klasa może linearyzować drzewo dziedziczenia, co oznacza, że ​​nawet jeśli dwoje rodziców na ścieżce powrotnej do wspólnego super-rodziców nominalnie są oboje rodzice, jeden jest "prawidłowy", a mianowicie: ten wymieniony na końcu. Ten schemat pozostawiłby zepsute pół-zainicjalizowane klasy, gdybyś mógł mieć (całkowicie generyczne) konstruktory, ale tak jak jest, nie musisz dwukrotnie osadzać klasy, a na stronie użycia możesz zignorować, ile dziedziczenia ma jakikolwiek stało się. To nie oznacza jednak, że sprawiają, że o wiele łatwiej rozumieć, co się stanie, gdy warstwa wiele cech na szczycie siebie, a jeśli dziedziczą zarówno B i C, nie można wybrać się niektóre z B implementacje i niektóre z wersji C.

Lepsze rozwiązanie polega na tym, że rozwiązuje niektóre z najbardziej poważnych uwag krytycznych dotyczących modelu C++. Czy to jest wystarczająco dobre, to kwestia gustu; wielu ludzi lubi smak wielokrotnego dziedziczenia C++ na tyle dobrze, by z niego korzystać.

+0

Wolę raczej określać niejednoznacznych członków, niż polegać na regule, która dokonuje nieoczywistych wyborów. – nclark

+0

@joeytwiddle - Właśnie zauważyłem, że złapałeś mój błąd ponad półtora roku temu! Naprawiono tekst. –

+0

@nclark - Nie dostaniesz nieoczywistych wyborów, chyba że już nadpisujesz, więc istnieje pewna ochrona przed nieoczywistymi wyborami. Ale gdy już masz przeciążone obiema gałęziami, tak, ostatnia z wymienionych jest wybierana automatycznie i można argumentować, że bycie wyraźnym byłoby również lepsze. (Jeśli chcesz tylko określić, jaką chcesz zastosować superklasę.) –

Powiązane problemy