Dziedziczenie czy atrybut

0

Witam,

Ostatnio spotkalem sie z ciekawym (przynajmniej dla mnie) problemem, sprawa wyglada tak:

Mamy klase, nazwijmy ja bazowa, ktora posiada okreslony zestaw metod i atrybutow sluzacych do manipulowania zestawem danych. Po stworzeniu klasy bazowej zaczalem implementowac inne klasy, ktore rozszerzaly funkcjonalnosc klasy bazowej o nowe metody, wiec od reki zastosowalem dziedziczenie.

Problem w tym, ze spotkalem sie z opinia, ze w tej sytuacji (gdy jedynie rozszerzam funkcjonalnosc nie nadpisujac zadnych odziedziczonych elementow) lepiej byloby w nowych klasach dodac atrybut typu klasy bazowej i za jego pomoca korzystac z jej funkconalnosci.

Co o tym myslicie? Czy zastosowanie dodatkowego atrybutu jest rzeczywiscie korzystniejsze niz dziedziczenie?

P.S. Przepraszam za brak polskich znakow ale aktualnie jestem za granica i nie mam jak przestawic klawiatury :)

0

To jest ciekawy problem -> kompozycja/agregacja czy dziedziczenie.

  • jeśli dziedzinowo występuje powiązanie między obiektami dwóch klas (tzn występuje tam relacja "jest rodzaju") to używamy dziedziczenia.
  • jeśli obiekty dwóch klas współdziałają, ale nie są dziedzinowo powiązane to często używamy kompozycji.
    Poza tym bierz pod uwagę fakt ograniczeń dziedziczenia wielokrotnego. O ile w C++ jest ono możliwe, o tyle jest dość niebezpieczne i czasem bardzo skomplikowane i często warto zamienić wielokrotne dziedziczenie na kompozycje / wielokrotne dziedziczenie interfejsu / wielokrotne jednokrotne dziedziczenie.
0
Shalom napisał(a)

To jest ciekawy problem -> kompozycja/agregacja czy dziedziczenie.

  • jeśli dziedzinowo występuje powiązanie między obiektami dwóch klas (tzn występuje tam relacja "jest rodzaju") to używamy dziedziczenia.
  • jeśli obiekty dwóch klas współdziałają, ale nie są dziedzinowo powiązane to często używamy kompozycji.
    Poza tym bierz pod uwagę fakt ograniczeń dziedziczenia wielokrotnego. O ile w C++ jest ono możliwe, o tyle jest dość niebezpieczne i czasem bardzo skomplikowane i często warto zamienić wielokrotne dziedziczenie na kompozycje / wielokrotne dziedziczenie interfejsu / wielokrotne jednokrotne dziedziczenie.

W moim przypadku klasy sa zdecydowanie powiazane relacja "jest rodzaju", wiec wyglada na to ze poprawnie zastosowalem dziedziczenie.

Intryguje mnie jeszcze jedno zagadnienie, mianowicie zuzycie pamieci. Czy kompozycja i dziedziczenie roznia sie pod tym wzgledem? Interesuja mnie nawet minimalne roznice, poniewaz system ktory projektuje jest systemem wbudowanym i naprawde musze sie troszczyc o zuzycie pamieci.

0

Tak czysto logicznie to masz albo
1 wskaźnik na obiekt i x + y atrybutów,
albo
1 wskaźnik na obiekt i x atrybutów + 1 wskaźnik na obiekt agregowany i y atrybutów obiektu agregowanego,
czyli różnica wynosi 1 wskaźnik.
Dobrze myślę?

0
plobpo napisał(a)

spotkalem sie z opinia, ze w tej sytuacji (gdy jedynie rozszerzam funkcjonalnosc nie nadpisujac zadnych odziedziczonych elementow) lepiej byloby w nowych klasach dodac atrybut typu klasy bazowej i za jego pomoca korzystac z jej funkconalnosci.

jakiś czas temu wyczytałem w książce nt. wzorców projektowych dość dobre wytłumaczenie co w takiej sytuacji zrobić. jeśli

  • klasa "potomna" ma uzupełniać funkcjonalność klasy rodzica,
  • rodzic ma mało metod i/lub znasz dobrze wszystkie i i jesteś pewien, że wywołanie dowolnej odziedziczonej (a nienadpisanej) metody nic nie zepsuje w klasie dziecka,
  • świadomie nie chcesz zawężać funkcjonalności rodzica (np. przez ukrycie części/większości metod),
    to użyj dziedziczenia.

jeśli masz hipotetyczną sytuację: masz klasę Graphics pozwalającą rysować punkty. robisz klasę Circle, która ma rysować okręgi. jeśli zastosujesz dziedziczenie, to obiekt Circle będzie pozwalać także na rysowanie punktów i inne bóg-wie-jakie rzeczy, na które pozwala klasa Graphics. logiczne, że tego nie chcesz, więc w tym przypadku nie robisz dziedziczenia, tylko enkapsulację/agregację.

@j_s_r_n: nie znam niuansów c++, ale każdy obiekt z metodami wirtualnymi ma tablicę vmt; więcej obiektów, mniej dziedziczenia, więcej tablic; mniej obiektów, więcej dziedziczenia, dłuższe tablice. imho różnice w użyciu pamięci i szybkości kodu będą nieznaczne, zresztą co za problem to przetestować (i opublikować wyniki pod postacią artykułu)?

0
ŁF napisał(a)
plobpo napisał(a)

spotkalem sie z opinia, ze w tej sytuacji (gdy jedynie rozszerzam funkcjonalnosc nie nadpisujac zadnych odziedziczonych elementow) lepiej byloby w nowych klasach dodac atrybut typu klasy bazowej i za jego pomoca korzystac z jej funkconalnosci.

jakiś czas temu wyczytałem w książce nt. wzorców projektowych dość dobre wytłumaczenie co w takiej sytuacji zrobić. jeśli

  • klasa "potomna" ma uzupełniać funkcjonalność klasy rodzica,
  • rodzic ma mało metod i/lub znasz dobrze wszystkie i i jesteś pewien, że wywołanie dowolnej odziedziczonej (a nienadpisanej) metody nic nie zepsuje w klasie dziecka,
  • świadomie nie chcesz zawężać funkcjonalności rodzica (np. przez ukrycie części/większości metod),
    to użyj dziedziczenia.

jeśli masz hipotetyczną sytuację: masz klasę Graphics pozwalającą rysować punkty. robisz klasę Circle, która ma rysować okręgi. jeśli zastosujesz dziedziczenie, to obiekt Circle będzie pozwalać także na rysowanie punktów i inne bóg-wie-jakie rzeczy, na które pozwala klasa Graphics. logiczne, że tego nie chcesz, więc w tym przypadku nie robisz dziedziczenia, tylko enkapsulację/agregację.

@j_s_r_n: nie znam niuansów c++, ale każdy obiekt z metodami wirtualnymi ma tablicę vmt; więcej obiektów, mniej dziedziczenia, więcej tablic; mniej obiektów, więcej dziedziczenia, dłuższe tablice. imho różnice w użyciu pamięci i szybkości kodu będą nieznaczne, zresztą co za problem to przetestować (i opublikować wyniki pod postacią artykułu)?

Opis rzeczywiscie sensowny, dziekuje.

Troche tylko obawiam sie niektorych wzorcow projektowych, jesli wezmiemy pod uwage efektywne wykorzystanie pamieci. Wybacz ze wracam do tego jak maniak, ale systemy wbudowane rzadza sie swoimi prawami. Spotkalem kiedys niesamowicie uzyteczny wzorzec nazwijmy go "Inteligentnym wskaznikiem", ktory (w wielkim uproszczeniu) opakowywal kazdy wskaznik w obiekt, ktory trzymal adres jako atrybut i zabezpieczal np. przed czytaniem z pustego adresu pamieci. Sek w tym, ze opakowujac wskaznik obiektem zuzywalismy pamiec i kiszka.

Wydaj mi sie ze rzeczywiscie najlepszym rozwiazaniem byloby sprawdzenie tego doswiadczalnie i jak znajde chwile wolnego czasu (tak pewnie kolo emerytury) sprawdze jak to wyglada w rzeczywistosci. Zastanawiam sie czy system operacyjny na ktorym bede to testowal ma znaczenie... wydaje mi sie ze nie, ale zawsze moge sprobwac na kilku roznych.

1 użytkowników online, w tym zalogowanych: 0, gości: 1