Chodzi to, że w momencie gdy definiujesz 'implementację' konstruktora/metody, to musisz znać już 'jak wyglądają typy wszystkich składowych'
Ale jak destruktor jest zdefiniowany w innej jednostce translacji, to już nagle implementacja konstruktora nie musi znać 'jak wyglądają typy wszystkich składowych'? 😄
A naprawiła? Coś takiego dalej się nie kompiluje, przynajmniej na GCC.
Ano naprawiła. Na GCC, proszę:
https://onlinegdb.com/r8sQPzGorMożesz się pobawić tym kodem. Przenieś definicję destruktora z powrotem do definicji
Helper
i zobacz jak nagle program się nie skompiluje. Albo zamień konstruktor na
Helper() = default
i zobacz jak nagle destruktor przestaje być potrzebny i program się kompiluje bez niego.
Po prostu przykład jest bez sensu. Jakakolwiek realna implementacja też by miała te same problemy, przez to że Number jest niekompletne w tym kontekście.
Dlatego właśnie podałem mój przykład złożony z 3 plików. Jest on jak najbardziej z sensem i zderzyłem się z tą sytuacją w moim kodzie. Miałem cykliczną zależność: Klasa A includowała klasę B, klasa B includowała klasę C, a klasa C trzymała wskaźnik na klasę A (klasa A była forward-declared). Wszystko działało do czasu, gdy postanowiłem zamienić "wskaźnik" na std::unique_ptr. Nagle się nie skompilowało. Wtedy natrafiłem na wpis blogowy:
https://ortogonal.github.io/cpp/forward-declaration-and-smart-pointers/, który pokazuje ten trick, że zdefiniowanie destruktora w innej jednostce translacji magiczne pozwala na stworzenie smart-pointera z forward zadeklarowanego typu, bez definicji. Autor wyjaśnia nawet dlaczego to działa. A mnie zastanawia (i to jest powód dla którego założyłem ten wątek na forum): dlaczego ten "trick" nie jest potrzebny, gdy konstruktor mojej klasy jest
= default
.
A tutaj przykład z "prawdziwego" projektu, gdzie występuje ten "problem":
https://github.com/TheCherno/Hazel/blob/master/Hazel/src/Hazel/Scene/Components.h#L89Autor w pliku Components.h w linii 87 robi forward-dekalrację
ScriptableEntity
. Plik ScriptableEntity.h includuje Entity.hpp. Plik Entity.h includuje Components.h. Czyli ta forward deklaracja na początku ratuje program przed cyklicznym includowaniem siebie nawzajem nagłówków. W kodzie z githuba, który podlinkowałem problem nie występuje, bo autor użył surowego wskaźnika
ScriptableEntity *
. Ja chciałem być "fancy" i zamienić to na
unique_ptr < ScriptableEntity >
. I wtedy napotkałem błąd kompilacji \(〇_o)/
Wyjaśnienia opisywane przez Was (za które bardzo dziękuję) mają częściowo sens. Chociaż moje dotychczasowe eksperymenty wskazują na taki wniosek: Zdefiniowanie własnego konstruktora w klasie
Helper
sprawia, że (z nadal nieznanego mi powodu) automatycznie generowany destruktor tejże klasy potrzebuje nagle definicji
Number
, aby się skompilować. I dlatego destruktor ten należy przenieść gdzieś indziej (np. do Helper.cpp), i tam zaincludować definicję
Number
. Tak jak to zrobiłem na przykładzie 🙃