Witam, mam problem z klasą szablonową z którą mam problem ponieważ utworzony obiekt nie widzi funkcji składowych tej klasy.
Wywala jedynie błąd
In function ZN7Magazyn12dodajKurieraE6Kurier
undefined reference to Lista::DodajNaKoncu(Kurier*)
Nie będę Ci mówił co masz robić bo to wolny kraj i jeszcze wolny internet. Moderatorom też nie zamierzam zawracać głowy pierdołami. Dla mnie to nie było śmieszne - ok są wątki, że inaczej nie można podejść do tematu i autora, ale to nie miejsca na to. Po prostu uważam, że tego typu komentarz był całkowicie zbędny, zwłaszcza, że w żadnym stopniu nie jest związany z problemem jakiego dotyczyć miał temat. Dlatego postanowiłem Ci zwrócić uwagę na to, a co z tym zrobisz to już mi obojętne.
Oczywiście miałem już deklarację ale skracając te klasy przypadkowo usunąłem tę linijkę.
Dopiero teraz kojarzę, że prawdopodobnie chodzi o utworzenie, jeszcze nie istniejącego, obiektu statycznego w Magazyn.cpp ale dodanie takiej linijki wywala prawie identyczny błąd
Lista<Kurier> Magazyn::listaKurierow;
In function _static_initialization_and_destruction_0
undefined reference to Lista<Kurier>::Lista(Kurier*)
Mistrzem C++ nie jestem, dużo doświadczenia w nim też nie mam, ale lubię ten język. Pomimo tego, że składnia często potrafi być bardzo nieczytelna, ale Ty do tego dodałeś jeszcze strasznie pogmatwany kod.
Czemu masz listę w liście? Nie dało się nazwać tego wszystkiego w bardziej czytelny sposób, momentami gubię się i nie wiem co jest do czego i w ogóle której klasy kod czytam. Czemu nie korzystasz z kontenerów dostępnych w std, przecież tam jest lista? - jeśli program do szkoły nie było pytania.
Wydaje mi się, że znalazłem jeden błąd. Jednak nie mam pojęcia czy jest on jakkolwiek związany z Twoim komunikatem błędu.
Konstruktor Lista: this->k = this->o;
po pierwsze o to argument konstruktora więc bez this, ale pewnie kompilator to ogarnął sam. Ważne jest to czego wskaźnik przypisujesz do k - czyli obiektu typu T. Później używasz go jak obiektu typu InnaL<T>, w funkcji DodajNaKoncu:
InnaL<T>* sK = k;
//...
k = sK->PNL();
Albo mocno czegoś nie ogarnąłem w kodzie, albo popełniłeś tu spory błąd. Dziwne tylko jest to, że kompilator w ogóle dopuścił do przypisania wskaźnika na inny obiekt - wydaje mi się, że powinien wywalić błąd. Aczkolwiek w przypadku polimorfizmu taki zabieg musi być dopuszczony, więc nie jestem pewny.
Projekt jest na uczelnię i pomyślałem sobie że może taka własna klasa będzie po prostu ładnie wyglądała i trochę przyuczę się szablonów.
Co do this to racja, przecież o jest wczytywany w konstruktorze
Ogólnie pozmieniałem nazwy by nie można było w łatwy sposób skojarzyć mojego kodu z moim kodem z internetu.
Tutaj mała ściąga
k-koniec
p-początek
d-dlugosc
a-aktualny
l-lista
Dziwne że kompilator nie zgłosił niezgodności typów przypisując InnaL<T>* adres obiektu T. Oczywiście że zamiast ‘o’ powinien tam być ‘p’ czyli początek
Lista to lista zarządzająca posiadająca adres początku i końca listy z możliwością dodawania elementów
InnaL to lista posiadająca adres poprzedniego i następnego elementu i własną wartością.
Zdaje mi się że tak powinna wyglądać lista dwukierunkowa ale mogę się mylić
Nawet usuwając cały środek ze wszystkich funkcji dalej wyskakuje błąd więc nie może to być problem z ciałem żadnej z funkcji
Spoko rozumiem wiem jak dziwni potrafią być prowadzący i że są w stanie googlować kod .
Podrzuć mi na priv cały kod, będzie łatwiej.
Generalnie lista dwukierunkowa nie koniecznie musi posiadać ostatni element, musisz mieć wskaźnik na pierwszy, aby nie zgubić listy. Dodatkowo każdy element listy powinien być opakowany w specjalny kontener. Taki kontener powinien mieć wskaźnik na obiekt który przechowuje, oraz na element następny (lista jedno kierunkowa). W przypadku listy dwukierunkowej dodatkowo wskaźnik na element poprzedni. Przez element mam na myśli wskaźnik na kontener opakowujący dodatkowo przechowywany obiekt w liście.
Sama klasa listy powinna tylko umieć iterować po takich elementach/kontenerach. W najostrzejszym przepadku lista powinna mieć wskaźnik tylko do pierwszego elementu. Oczywiście dla optymalizacji jeśli często przesuwasz się do tyłu po liście może też mieć ostatni element.
Można do takiej listy stworzyć jeszcze klasę iteratora, który dodatkowo będzie przechowywał wskaźnik na ostatnio odczytywany element, plus będzie mógł być interowany np +1 spowoduje przesunięcie listy o 1 do przodu.
Zabawy co nie miara i można wymyślać i wymyślać. Dużo zależy od przeznaczenia listy i sposobu jej używania.
Nie umiem znaleźć błędu. Twój kod zawiera sporo błędów i musiałem się trochę na kombinować, żeby się w ogóle chciała reszta klas skompilować.
Robisz wiele rzeczy w dziwny sposób, z czego może wynikać problem. To też powoduje, że ciężko mi znaleźć błąd. Nie mam obecnie możliwości poświęcenia za dużo czasu na szukanie problemu, zwłaszcza, że trzeba by było po kolei rozwiązywać problemy. Generalnie napisałeś dużo kodu który nie do końca działa i często nie jest skończony. Bardzo wiele rzeczy masz zakomentowanych tylko po to by w ogóle się skompilowało. To wszystko utrudnia znalezienie przyczyny problemu.
Od siebie mogę dodać, że raczej błąd nie jest w klasach szablonowych, a w klasie magazyn w której te obiekty tworzysz. Chociaż nie dam sobie głowy uciąć bo wszystko wygląda tam w miarę poprawnie.
Taka pierwsza rzecz jaka w oczy mi się rzuciła już w kodzie który tutaj wstawiłeś to choćby ten konstruktor:
Czemu nie przeciążasz konstrutkora i lepiej nie organizujesz jego argumenty - nieobowiązkowe powinny być na końcu, a teraz masz sytuację, że obowiązkowy jest dosłownie w środku i musisz wywoływać konstruktor w taki sposób:
Ogólnie to jest projekt nad którym pracują 4 osoby z czego tylko jedna dodała bodajże kilkanaście linijek kodu a resztę sam zrobiłem po to by można by mogli od czegoś zacząć. W komentarzach też są pozostałości z naprawdę wstępnych rozważań jakby mogło to być zrobione(wizja programu ciągle się rozwija)
Co do kolejności argumentów to na porządkowanie zostawiłem na później a w takim zapisie łatwiej było odczytywać informacje - (poprzedni,aktualny,nastepny) - (nullptr,o,nullptr), póki co to dla mnie najważniejsze jest to aby działało.
Ogólnie to skaczę pomiędzy różnymi językami i nie robiłem zbyt skomplikowanych projektów w c++ więc takie błędy no… muszą być. Z czasem postaram się to poprawić
Jeszcze raz wielkie dzięki za rady i poświęcony czas
@Fizyda To nie jest kwestia konstruktora, tylko sposobu w jaki działają szablony. Szablon jest tutaj informacja, jak kompilator ma tworzyć klasy na podstawie przekazanego parametru.
Jeśli nie robimy tego w pliku nagłowkowym, to kompilator widzi deklaracje - wszystko skompiluje się poprawnie. Niestety linker nie znajdzie nigdzie definicji. Stąd:
undefined reference to Lista::DodajNaKoncu(Kurier*)
Problem można też rozwiązać trzymając się osobnego pliku cpp:
Ze swojej strony polecam jeszcze przyjrzeć się temu co znajdzie się w pliku Lista.o po kompilacji (np. polecenie nm na Linuksie). Widać jakie zostały wygenerowane symbole. Jeśli zamieścimy deklarację jedynie dla int:
0000000000000000 W _ZN5ListaIiE12DodajNaKoncuEv
0000000000000000 W _ZN5ListaIiEC1EPi
0000000000000000 W _ZN5ListaIiEC2EPi
0000000000000000 n _ZN5ListaIiEC5EPi
Jeśli dla int oraz float:
0000000000000000 W _ZN5ListaIfE12DodajNaKoncuEv
0000000000000000 W _ZN5ListaIfEC1EPf
0000000000000000 W _ZN5ListaIfEC2EPf
0000000000000000 n _ZN5ListaIfEC5EPf
0000000000000000 W _ZN5ListaIiE12DodajNaKoncuEv
0000000000000000 W _ZN5ListaIiEC1EPi
0000000000000000 W _ZN5ListaIiEC2EPi
0000000000000000 n _ZN5ListaIiEC5EPi
Widać tutaj, do czego będzie w stanie odnosić się linker.
No tak, ale deklaracja szablonu tylko tutaj na forum była podana “w jednym pliku”. Normalnie wszystko było poprawnie pod tym względem. Dodatkowo popatrz na kod, w komentarzach masz opisane co z jakiego pliku pochodzi, więc problemem nie było miejsce umieszczenia deklaracji szablonu, a źle napisana definicja konstruktora - przynajmniej na to wychodzi.
Często na forach czy innych stronach pomocy ludzie wrzucają kod w jeden listing i tylko dodają informację z jakiego pliku co pochodzi.
Ehh muszę odpocząć, bo jest rano, a ja nie ogarniam. Teraz doczytałem o definicji w plikach nagłówkowych.
Przyznam szczerze, że z szablonami w C++ miałem tak mało kontaktu, że śmiało mogę powiedzieć, że wcale. No ale dużo się z Twoich postów dowiedziałem, dzięki .