Uważam, że pliki nagłówkowe są przydatne podczas przeglądania plików źródłowych C ++, ponieważ dają one „podsumowanie” wszystkich funkcji i elementów danych w klasie. Dlaczego tak wiele innych języków (takich jak Ruby, Python, Java itp.) Nie ma takiej funkcji? Czy jest to obszar, w którym przydaje się gadatliwość C ++?
20
Odpowiedzi:
Pierwotnym celem plików nagłówkowych było umożliwienie kompilacji jednoprzebiegowej i modułowości w C. Deklarowanie metod przed ich użyciem pozwoliło tylko na pojedyncze przejście kompilacji. Ten wiek już dawno minął, ponieważ nasze potężne komputery są w stanie wykonywać kompilacje wieloprzebiegowe bez żadnych problemów, a czasem nawet szybciej niż kompilatory C ++.
C ++ jest wstecznie kompatybilny z C, aby zachować pliki nagłówkowe, ale dodał wiele z nich, co spowodowało dość problematyczny projekt. Więcej w FQA .
W przypadku modułowości pliki nagłówkowe były potrzebne jako metadane dotyczące kodu w modułach. Na przykład. jakie metody (oraz w klasach C ++) są dostępne w jakiej bibliotece. Było oczywiste, że programista napisał to, ponieważ czas kompilacji był kosztowny. W dzisiejszych czasach kompilator nie generuje tych metadanych z samego kodu. Języki Java i .NET robią to normalnie.
Więc nie. Pliki nagłówkowe nie są dobre. To były czasy, kiedy wciąż mieliśmy kompilator i linker na osobnych dyskietkach, a kompilacja zajęła 30 minut. W dzisiejszych czasach przeszkadzają i są oznaką złego projektu.
źródło
Chociaż mogą być przydatne jako forma dokumentacji, system plików nagłówkowych jest wyjątkowo nieefektywny.
C został zaprojektowany tak, aby każdy przebieg kompilacji tworzył jeden moduł; każdy plik źródłowy jest kompilowany w osobnym uruchomieniu kompilatora. Z drugiej strony pliki nagłówkowe są wstrzykiwane do tego kroku kompilacji dla każdego pliku źródłowego, który się do nich odwołuje.
Oznacza to, że jeśli twój plik nagłówkowy jest zawarty w 300 plikach źródłowych, to jest analizowany i kompilowany w kółko, 300 razy, podczas tworzenia programu. Dokładnie to samo z tym samym rezultatem w kółko. Jest to ogromna strata czasu i jest jednym z głównych powodów, dla których tworzenie programów w językach C i C ++ trwa tak długo.
Wszystkie współczesne języki celowo unikają tej absurdalnej małej nieefektywności. Zamiast tego, zwykle w skompilowanych językach, niezbędne metadane są przechowywane w danych wyjściowych kompilacji, umożliwiając skompilowanemu plikowi działanie jako rodzaj odnośnika szybkiego wyszukiwania opisującego zawartość skompilowanego pliku. Wszystkie zalety pliku nagłówkowego, tworzonego automatycznie, bez dodatkowej pracy z Twojej strony.
Alternatywnie w tłumaczonych językach, każdy ładowany moduł pozostaje w pamięci. Odwołanie lub dołączenie lub wymaganie biblioteki spowoduje odczytanie i skompilowanie powiązanego kodu źródłowego, który pozostaje rezydentny aż do zakończenia programu. Jeśli potrzebujesz go również w innym miejscu, nie musisz wykonywać żadnej dodatkowej pracy, ponieważ został już załadowany.
W obu przypadkach można „przeglądać” dane utworzone w tym kroku za pomocą narzędzi języka. Zazwyczaj IDE będzie miało przeglądarkę klas. A jeśli język ma REPL, można go często użyć do wygenerowania podsumowania dokumentacji załadowanych obiektów.
źródło
Nie jest jasne, co masz na myśli, przeglądając plik w poszukiwaniu funkcji i członków danych. Jednak większość IDE zapewnia narzędzia do przeglądania klasy i przeglądania członków danych klasy.
Na przykład: Visual Studio ma
Class View
iObject browser
ładnie zapewnia żądaną funkcjonalność. Jak w poniższych zrzutach ekranu.źródło
Dodatkową wadą plików nagłówkowych jest to, że program zależy od kolejności ich włączenia, a programista musi podjąć dodatkowe kroki w celu zapewnienia poprawności.
To w połączeniu z systemem makro C (odziedziczonym przez C ++) prowadzi do wielu pułapek i mylących sytuacji.
Aby to zilustrować, jeśli jeden nagłówek zdefiniował jakiś symbol za pomocą makr do jego użycia, a inny nagłówek użył symbolu w inny sposób, na przykład nazwę funkcji, wówczas kolejność uwzględnienia miałaby duży wpływ na końcowy wynik. Istnieje wiele takich przykładów.
źródło
Zawsze lubiłem pliki nagłówkowe, ponieważ zapewniają one interfejs do implementacji, wraz z dodatkowymi informacjami, takimi jak zmienne klas, wszystko w jednym łatwym do przeglądania pliku.
Widzę dużo kodu C # (który nie wymaga 2 plików na klasę) napisanych przy użyciu 2 plików na klasę - jeden z rzeczywistą implementacją klasy, a drugi z interfejsem. Ten projekt jest dobry do kpienia (niezbędny w niektórych systemach) i pomaga zdefiniować dokumentację klasy bez konieczności używania IDE do przeglądania skompilowanych metadanych. Poszedłem tak daleko, by powiedzieć, że to dobra praktyka.
Więc C / C ++ nakazujący ekwiwalent (swego rodzaju) interfejsu w plikach nagłówkowych jest dobrą rzeczą.
Wiem, że istnieją zwolennicy innych systemów, którzy ich nie lubią z takich powodów, jak: „trudniej jest po prostu zhakować kod, jeśli trzeba umieścić rzeczy w 2 plikach”, ale moje podejście jest takie, że samo hakowanie kodu i tak nie jest dobrą praktyką , a kiedy zaczniesz pisać / projektować kod z odrobiną przemyślenia, wtedy oczywiście będziesz definiować nagłówki / interfejsy.
źródło
Powiedziałbym, że pliki nagłówkowe nie są świetne, ponieważ mętnią interfejs i implementację. Ogólnym celem programowania, a zwłaszcza OOP, jest zdefiniowanie interfejsu i ukrycie szczegółów implementacji, ale plik nagłówkowy C ++ pokazuje zarówno metody, dziedziczenie, jak i elementy publiczne (interfejs), a także metody prywatne i elementy prywatne (część wdrożenia). Nie wspominając o tym, że w niektórych przypadkach wstawiasz kod lub konstruktory w pliku nagłówkowym, a niektóre biblioteki zawierają kod szablonu w nagłówkach, który naprawdę miesza implementację z interfejsem.
Uważam, że pierwotnym celem było umożliwienie kodowi korzystania z innych bibliotek, obiektów itp. Bez konieczności importowania całej zawartości skryptu. Wystarczy nagłówek, aby skompilować i połączyć. Oszczędza w ten sposób czas i cykle. W takim przypadku jest to przyzwoity pomysł, ale jest to tylko jeden ze sposobów rozwiązania tych problemów.
Jeśli chodzi o przeglądanie struktury programu, większość IDE zapewnia taką możliwość, a istnieje wiele narzędzi, które wykopią interfejsy, przeprowadzą analizę kodu, dekompilację itp., Abyś mógł zobaczyć, co dzieje się pod okładkami.
A dlaczego inne języki nie implementują tej samej funkcji? Cóż, ponieważ inne języki pochodzą od innych ludzi, a ci projektanci / twórcy mają inną wizję tego, jak powinny działać.
Najlepszą odpowiedzią jest trzymanie się zadania, które musisz wykonać, i sprawia, że jesteś szczęśliwy.
źródło
W wielu językach programowania, gdy program jest podzielony na wiele jednostek kompilacji, kod w jednej jednostce będzie mógł używać rzeczy zdefiniowanych w innym, tylko jeśli kompilator ma pewne środki, aby wiedzieć, co to jest. Zamiast wymagać, aby kompilator przetwarzający jedną jednostkę kompilacji sprawdzał cały tekst każdej jednostki kompilacji, która definiuje wszystko używane w bieżącej jednostce, najlepiej, aby kompilator odbierał, podczas przetwarzania każdej jednostki, pełny tekst jednostki, która ma być kompilowana z niewielką ilością informacji od wszystkich innych.
W C programista jest odpowiedzialny za utworzenie dwóch plików dla każdej jednostki - jeden zawierający informacje, które będą potrzebne tylko podczas kompilacji tej jednostki, a drugi zawierający informacje, które będą również potrzebne podczas kompilacji innych jednostek. Jest to dość paskudny, zhackowany projekt, ale pozwala uniknąć potrzeby, aby standard językowy określał wszystko, w jaki sposób kompilatory powinny generować i przetwarzać pliki pośrednie. Wiele innych języków stosuje inne podejście, w którym kompilator generuje z każdego pliku źródłowego plik pośredni opisujący wszystko w tym pliku źródłowym, który powinien być dostępny dla kodu zewnętrznego. Takie podejście pozwala uniknąć konieczności powielania informacji w dwóch plikach źródłowych, ale wymaga, aby platforma kompilacji zdefiniowała semantykę plików w sposób, który nie jest wymagany dla C.
źródło