Dlaczego deklaracja forward jest konieczna w C ++
Kompilator chce się upewnić, że nie popełniłeś błędów ortograficznych ani nie przekazałeś niewłaściwej liczby argumentów do funkcji. Nalega więc, aby przed użyciem zobaczyła deklarację „dodaj” (lub dowolnego innego typu, klasy lub funkcji).
To naprawdę pozwala kompilatorowi lepiej sprawdzać poprawność kodu i porządkować luźne końce, dzięki czemu może tworzyć ładnie wyglądający plik obiektowy. Jeśli nie musisz przekazywać dalej deklaracji, kompilator wygeneruje plik obiektowy, który będzie musiał zawierać informacje o wszystkich możliwych zgadnięciach dotyczących tego, czym może być funkcja „dodaj”. A linker musiałby zawierać bardzo sprytną logikę, aby spróbować ustalić, który „add” rzeczywiście chcesz wywołać, gdy funkcja „add” może znajdować się w innym pliku obiektowym, linker łączy się z tym, który używa add do produkcji dll lub exe. Możliwe, że linker otrzyma niewłaściwe dodanie. Powiedzmy, że chciałeś użyć int add (int a, float b), ale przypadkowo zapomniałeś go napisać, ale linker znalazł już istniejący int add (int a, int b) i pomyślałem, że to było właściwe i użyłem tego zamiast tego. Twój kod się skompiluje, ale nie będzie działał zgodnie z oczekiwaniami.
Tak więc, aby zachować jasność rzeczy i uniknąć zgadywania itp., Kompilator nalega, aby zadeklarować wszystko przed użyciem.
Różnica między deklaracją a definicją
Nawiasem mówiąc, ważne jest, aby znać różnicę między deklaracją a definicją. Deklaracja po prostu daje wystarczającą ilość kodu, aby pokazać, jak coś wygląda, więc dla funkcji jest to typ zwracany, konwencja wywoływania, nazwa metody, argumenty i ich typy. Ale kod metody nie jest wymagany. Do definicji potrzebna jest deklaracja, a także kod funkcji.
W jaki sposób deklaracje forward mogą znacznie skrócić czas kompilacji
Możesz pobrać deklarację funkcji do bieżącego pliku .cpp lub .h, # włączając nagłówek, który już zawiera deklarację funkcji. Może to jednak spowolnić kompilację, zwłaszcza jeśli #włączasz nagłówek do .h zamiast .cpp twojego programu, ponieważ wszystko co #include .h piszesz kończy się # obejmowaniem wszystkich nagłówków też napisałeś #include. Nagle kompilator ma # zawarte strony i strony kodu, które musi skompilować, nawet jeśli chcesz użyć tylko jednej lub dwóch funkcji. Aby tego uniknąć, możesz użyć deklaracji przesyłania dalej i po prostu sam wpisać deklarację funkcji u góry pliku. Jeśli używasz tylko kilku funkcji, może to naprawdę przyspieszyć twoją kompilację w porównaniu do zawsze #włączenie nagłówka. W przypadku naprawdę dużych projektów
Przerywaj odniesienia cykliczne, w których obie definicje wykorzystują się nawzajem
Ponadto deklaracje forward mogą pomóc w przerwaniu cykli. To tutaj dwie funkcje próbują się nawzajem używać. Kiedy tak się dzieje (i jest to całkowicie słuszna czynność), możesz # dołączyć jeden plik nagłówka, ale ten plik nagłówka próbuje # dołączyć plik nagłówka, który obecnie piszesz .... który następnie # zawiera drugi nagłówek , który # obejmuje ten, który piszesz. Utknąłeś w sytuacji z kurczakiem i jajkiem, a każdy plik nagłówkowy próbuje ponownie #include drugi. Aby rozwiązać ten problem, możesz zadeklarować w przód potrzebne części w jednym z plików i pozostawić #include poza tym plikiem.
Na przykład:
Plik Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
File Wheel.h
Hmm ... tutaj wymagana jest deklaracja Car, ponieważ Wheel ma wskaźnik do Car, ale Car.h nie może zostać tutaj uwzględniony, ponieważ spowodowałoby to błąd kompilatora. Gdyby uwzględniono Car.h, wówczas spróbowałby uwzględnić Wheel.h, który obejmowałby Car.h, który obejmowałby Wheel.h, i to trwałoby wiecznie, więc zamiast tego kompilator zgłasza błąd. Rozwiązaniem jest zamiast tego zadeklarować samochód zamiast:
class Car; // forward declaration
class Wheel
{
Car* car;
};
Jeśli klasa Wheel ma metody, które muszą wywoływać metody car, metody te można by zdefiniować w Wheel.cpp, a Wheel.cpp może teraz obejmować Car.h bez powodowania cyklu.