Uczę się do egzaminu i mam pytanie, na które staram się udzielić odpowiedzi.
Dlaczego nie istnieje żadna klasa bazowa iteratorów, z której dziedziczą wszystkie inne iteratory?
Domyślam się, że mój nauczyciel odnosi się do struktury hierarchicznej z odwołania cpp „ http://prntscr.com/mgj542 ” i musimy podać inny powód niż dlaczego?
Wiem, jakie są (iteratory) iteratory i że są używane do pracy na kontenerach. Z tego, co rozumiem ze względu na różne możliwe bazowe struktury danych, różne kontenery mają różne iteratory, ponieważ na przykład możesz losowo uzyskać dostęp do tablicy, ale nie połączona lista i różne kontenery wymagają różnych sposobów przemieszczania się po nich.
Prawdopodobnie są to specjalistyczne szablony w zależności od pojemnika, prawda?
Odpowiedzi:
Otrzymałeś już odpowiedzi wskazujące, dlaczego nie jest konieczne, aby wszystkie iteratory dziedziczyły z jednej klasy podstawowej Iterator. Ale poszedłem jeszcze dalej. Jednym z celów C ++ jest abstrakcja przy zerowym koszcie wykonania.
Jeśli iteratory działały przez wszystkich dziedziczących po wspólnej klasie bazowej i używały funkcji wirtualnych w klasie bazowej do definiowania interfejsu, a klasy pochodne zapewniały implementacje tych funkcji wirtualnych, które mogłyby (i często dodawałyby) znaczny czas działania koszty ogólne związane z operacjami.
Rozważmy na przykład prostą hierarchię iteratorów, która korzysta z funkcji dziedziczenia i funkcji wirtualnych:
Dajmy więc szybki test:
[uwaga: w zależności od kompilatora może być konieczne wykonanie nieco więcej czynności, takich jak zdefiniowanie kategorii iterator_category, typ różnicowy, odwołanie itd., aby kompilator zaakceptował iterator.]
Wyjście to:
[Oczywiście, jeśli uruchomisz kod, wyniki nie będą dokładnie do nich pasować.]
Nawet w tym prostym przypadku (i wykonując tylko około 80 przyrostów i porównań) dodaliśmy około 60% kosztów ogólnych do prostego wyszukiwania liniowego. Zwłaszcza, gdy iteratory zostały pierwotnie dodane do C ++, sporo osób po prostu nie zaakceptowałoby projektu z tak dużym obciążeniem. Prawdopodobnie nie zostałyby ujednolicone, a nawet gdyby tak było, praktycznie nikt by ich nie użył.
źródło
Różnica jest między Co coś jest, a jak coś zachowuje.
Wiele języków próbuje połączyć te dwa języki razem, ale są to dość różne rzeczy.
Co to jest i co to jest ...
Jeśli wszystko odziedziczy
object
po tym, pojawiają się pewne korzyści, takie jak: dowolna zmienna obiektu może posiadać dowolną wartość. Ale to też jest pocieranie, wszystko musi zachowywać się ( jak )object
i wyglądać jak ( co )object
.Ale:
Albo ten
object
typ stanie się zasadniczo bezużyteczny - z powodu braku podobieństwa między obiektami we wszystkich możliwych instancjach. Albo będą istnieć obiekty, które mają złamaną / rogową w buty / absurdalną definicję jakiejś przypuszczalnej uniwersalnej własności, naobject
której zachowuje się niemal uniwersalne zachowanie, z wyjątkiem kilku głupków.Jeśli co nie jest związane z How
Alternatywnie możesz zachować Co i jak osobno. Potem kilka różnych typów (z nic wspólnego w ogóle what ) wszystko może zachowywać się w taki sam sposób, jak wynika z współpracownik How . W tym sensie idea an
Iterator
nie jest konkretnym co , ale jak . W szczególności Jak wchodzisz w interakcję z rzeczą, gdy jeszcze nie wiesz, z czym masz do czynienia.Java (i podobne) umożliwiają podejście do tego przy użyciu interfejsów. Interfejs w tym względzie opisuje środki komunikacji i pośrednio protokół komunikacji i działania, które należy stosować. Wszelkie Co który deklaruje się być danego Jak stwierdza, że obsługuje on odpowiednią komunikację i działania przedstawionego przez protokół. Pozwala to każdy współpracownik polegać na how i nie ugrzęznąć określając dokładnie, które What „s mogą być użyte.
C ++ (i podobne) umożliwiają podejście do tego poprzez pisanie kaczych znaków. Szablon nie dba o to, czy typ współpracujący zadeklaruje, że zachowuje się, tak jak w danym kontekście kompilacji, z którym obiekt może wchodzić w interakcję w określony sposób. Pozwala to na używanie wskaźników tego samego kodu i wskaźników C ++ oraz obiektów przekraczających określone operatory. Ponieważ spełniają listę kontrolną, którą należy uznać za równoważną.
Typ bazowy nawet nie muszą być iteracji pojemnik, może to być dowolna co . Dodatkowo pozwala niektórym współpracownikom być jeszcze bardziej ogólnym, wyobraź sobie, że funkcja potrzebuje tylko
a++
, iterator może to zaspokoić, podobnie jak wskaźnik, liczba całkowita, aby każdy obiekt mógł się zaimplementowaćoperator++
.Niedostateczna i nadmierna specyfikacja
Problem z obydwoma podejściami jest niezgodny ze specyfikacją.
Korzystanie z interfejsu wymaga, aby obiekt zadeklarował, że obsługuje dane zachowanie, co oznacza również, że twórca musi go nasycić od samego początku. Powoduje to, że niektóre Co „s, aby nie dokonać cięcia, gdyż nie ogłoszono go. Oznacza to również, że zawsze Co ma wspólnego przodka, interfejs reprezentujący How . To przywraca pierwotny problem
object
. Powoduje to, że współpracownicy nadmiernie określają swoje wymagania, jednocześnie powodując, że niektóre obiekty są niezdatne do użytku z powodu braku deklaracji lub są ukrytymi problemami, ponieważ oczekiwane zachowanie jest źle zdefiniowane.Korzystanie z szablonu wymaga współpracy współpracownika z całkowicie nieznanym What , a poprzez interakcje definiuje How . W pewnym stopniu utrudnia to pisanie współpracowników, ponieważ musi analizować Co za prymitywy komunikacyjne (funkcje / pola / itp.), Unikając błędów kompilacji, lub przynajmniej wskazywać, w jaki sposób dane Czego nie spełniają jego wymagania dotyczące Jak . Pozwala to na współpracownika żądać absolutnego minimum z danym Co , pozwalając najszerszy zakres co „s ma być używany. Niestety ma to tę wadę, że pozwala na bezsensowne wykorzystanie obiektów, które technicznie zapewniają prymityw komunikacyjny dla danegoJak , ale nie postępuj zgodnie z domniemanym protokołem pozwalającym na występowanie różnego rodzaju złych rzeczy.
Iteratory
W tym przypadku
Iterator
jest Jak to jest skrótem opisu interakcji. Wszystko, co pasuje do tego opisu, jest z definicji anIterator
. Knowing How pozwala nam pisać ogólne algorytmy i mieć krótką listę „ Jak podano konkretne Co ”, które należy podać, aby algorytm działał. Że lista jest funkcja / Właściwości / etc, ich realizacja uwzględnia specyficznych Co to jest rozpatrywana przez algorytm.źródło
Ponieważ C ++ nie musi mieć (abstrakcyjnych) klas bazowych do polimorfizmu. Ma podsieci strukturalne, a także podsieci nominalne .
Myląco w szczególnym przypadku iteratorów poprzednie normy zdefiniowane
std::iterator
jako (w przybliżeniu)To znaczy, że jest jedynie dostawcą wymaganych typów członków. Nie zachowywał się w środowisku uruchomieniowym i był przestarzały w C ++ 17
Zauważ, że nawet to nie może być wspólną podstawą, ponieważ szablon klasy nie jest klasą, każda instancja jest niezależna od innych.
źródło
Jednym z powodów jest to, że iteratory nie muszą być instancjami klasy. Wskaźniki są na przykład bardzo dobrymi iteratorami w wielu przypadkach, a ponieważ są prymitywami, nie mogą dziedziczyć po niczym.
źródło