Jak Herb Sutter i Andrei Alexandrescu wyjaśnić w swojej książce C++ Coding Standards (item 34), dziedziczenie jest jednym z najbardziej napiętych stosunków C++, która pozwala na używanie dwóch klasach - To jest drugi tylko do friend
relacji między klasami.
Zgodnie z S.O.L.I.D principles of OO udany projekt powinien mieć na celu luźne połączenie między klasami - to sugeruje utrzymywanie zależności do minimum; co z kolei oznacza, że dziedziczenie jest narzędziem, które powinno być używane z ostrożnością.
Oczywiście, zależności generalnie muszą istnieć gdzieś, więc rozsądny kompromis może być dziedziczenie z klas bez wdrożenia na wszystkich (analogicznie do tzw interface
s w językach takich jak C# i Java). na przykład
class IDriveable
{
public:
virtual void GoForward() = 0;
virtual void GoBackward() = 0;
};
class Car : public IDriveable { /* etc. */ };
class Bus : public IDriveable { /* etc. */ };
class Train : public IDriveable { /* etc. */ };
Z takim podejściem, jeśli masz elementy kodu które są ponownie wykorzystywane między kilkoma napędzane klas, byś zazwyczaj korzystają składu lub jakąś inną słabszą zależność wyeliminować powtarzające się kod.
np. Może chcesz ponownie użyć kodu do TurnLeft
dla Bus
i Car
ale nie Train
gdzie obrót w lewo jest nielogiczne, więc TurnLeft
może skończyć się w osobnej klasy, który jest członkiem-of Bus
i Car
.
- Ponadto każda funkcja, która może wiedzieć o wszystkich niejasno związanych klas byłoby na zewnątrz heirarchy klasy, tylko świadomość interfejsu/base zamiast szczegółów implementacji sedna.
Końcowym rezultatem może być niewielka ilość dodatkowego kodu do kompozycji, ale często mniej złożonego projektu, zazwyczaj łatwiejszego do zarządzania. Nie ma żadnych sztywnych zasad projektowania takiego kodu, ponieważ zależy on wyłącznie od unikalnych problemów, które próbujesz rozwiązać.
Istnieją inne sposoby ponownego użycia kodu bez napięty sprzężenia też - szablony pozwalają niejawnie definiowania interfejsów bez pustych klas zawierające czysty virtual
funkcje (szablony zapewnienia dodatkowego bezpieczeństwa typ - co jest bardzo dobry sprawa, ale są składniowo trochę bardziej złożony);
Są też sposoby, dzięki którym można użyć kodu std::function
i lambdas w celu ponownego użycia kodu w bardziej funkcjonalnym stylu - ponownie zwykle nie występują ścisłe zależności podczas przechodzenia wokół obiektów funkcyjnych.
Dzięki za odpowiedzi chłopaki! Naprawdę je doceniam. Powodem, dla którego rozważałem używanie dziedziczenia zamiast kompozycji, jest to, że muszę również zmodyfikować niektóre zachowania w A i B. Również ja naprawdę nie chcę edytować A i B. – user1657624