2017-12-19 206 views
6

Na przykład, kiedy definiuję plik klasy w C++, zawsze umieszczałem ciała funkcji w plikach nagłówkowych klasy (.h) wraz z definicją klasy. Plik kodu źródłowego (.cpp) jest tym z funkcją main(). Teraz jest to często robione wśród programistów pro C++ lub są zgodne z konwencją oddzielnych plików kodu nagłówkowego/źródłowego.Dlaczego ciał funkcji w C/C++ umieszczane są w osobnych plikach kodu źródłowego zamiast nagłówków?

Co do Natywnego C, to zauważam, że zrobiłem to w GCC (i oczywiście dla nagłówków w Visual Studio dla Windowsa).

Czy to tylko konwencja? Czy istnieje ku temu powód?

+0

To tylko konwencja. –

+3

@JakeFreeman: Konwencje często mają powody. W tym przypadku istnieje wiele naprawdę dobrych powodów. –

+0

Zobacz: https://stackoverflow.com/questions/875479/what-is-the-difference-between-a-cpp-file-and-a---f- file –

Odpowiedz

18

organy funkcyjne są umieszczane w .cpp plików do osiągnięcia następujących celów:

  1. Aby dokonać parse kompilatora i skompilować je tylko raz, a nie zmuszając go skompilować je znowu, znowu i znowu wszędzie nagłówek plik jest dołączony. Dodatkowo, w przypadku implementacji nagłówka linker będzie musiał później wykrywać i eliminować identyczne funkcje zewnętrznego połączenia przychodzące w różnych plikach obiektowych.

    Wstępne kompilacje nagłówków wdrożone przez wiele nowoczesnych kompilatorów mogą znacznie zmniejszyć zmarnowany wysiłek wymagany do powtórnej rekompilacji tego samego pliku nagłówkowego, ale nie eliminują całkowicie problemu.

  2. Aby ukryć implementacje tych funkcji przed przyszłymi użytkownikami modułu lub biblioteki. Techniki ukrywania implementacji pomagają w egzekwowaniu pewnych dyscyplin programowania, co zmniejsza pasożytnicze współzależności między modułami, a tym samym prowadzi do czystszego kodu i szybszych czasów kompilacji.

    Powiedziałbym nawet, że nawet jeśli użytkownicy mają dostęp do pełnego kodu źródłowego biblioteki (tj. Nic nie jest naprawdę "ukryte" od nich), czyste oddzielenie między tym, co powinno być widoczne przez pliki nagłówkowe, a tym, co nie jest Powinien być widoczny, jest korzystny dla właściwości autokumentowania biblioteki (chociaż taka separacja jest możliwa do osiągnięcia również w bibliotekach tylko nagłówkowych).

  3. Aby niektóre funkcje były "niewidoczne" dla świata zewnętrznego (tj. Wewnętrzne powiązania, nie odnoszące się bezpośrednio do przykładu przy użyciu metod klasowych).

  4. Nielinearne funkcje rezydujące w określonej jednostce tłumaczeniowej mogą podlegać pewnym optymalizacjom zależnym od kontekstu. Na przykład dwie różne funkcje z identycznymi częściami ogonowymi mogą skończyć się "udostępnianiem" kodu maszynowego realizującego te identyczne ogony.

    Funkcje zadeklarowane jako wstawiane w plikach nagłówkowych są kompilowane wiele razy w różnych jednostkach tłumaczeniowych (tj. W różnych kontekstach) i muszą być później wyeliminowane przez linker, co utrudnia (jeśli w ogóle możliwe) skorzystanie z takie możliwości optymalizacji.

  5. Inne powody, dla których mogłem przeoczyć.

+1

Również w celu umożliwienia dystrybucji bibliotek z ich odpowiednimi nagłówkami, aby inni mogli używać ich w swoich kodach. –

+0

Doskonała odpowiedź. Dziękuję za wyjaśnienie faktycznego uzasadnienia, ponieważ nie jest to tylko konwencja, ale wydajność obliczeniowa. – SavedbyZer0

4

Jest to konwencja, ale zależy również od konkretnych potrzeb. Na przykład, jeśli piszesz bibliotekę, którą chcesz, aby funkcja była szybka (inline) i projektujesz bibliotekę, aby inni mogli ją używać jako zwykłą bibliotekę header only, wtedy możesz napisać cały swój kod w pliku nagłówkowym (s) samo.

Z drugiej strony; jeśli piszesz bibliotekę, która będzie połączona statycznie lub dynamicznie i próbujesz hermetyzować dane wewnętrznego obiektu od użytkownika. Twoje funkcje - funkcje należące do klasy itp. Zostałyby zapisane w taki sposób, że robią to, co powinny, w taki sposób, aby użytkownik kodu bibliotecznego nie musiał się martwić o szczegóły rzeczywistej implementacji tej części, która jest ukryta. Wszystko, co powinni wiedzieć o swoich funkcjach, a klasy to ich interfejsy. W ten sposób będziesz miał zarówno pliki nagłówkowe, jak i pliki implementacyjne.

Jeśli umieścisz definicje funkcji w plikach nagłówków wraz z ich deklaracjami, będą one wstawiane i powinny działać szybciej, ale twój plik wykonywalny będzie większy i będzie musiał być skompilowany za każdym razem. Szczegóły implementacji są również narażone na działanie użytkownika.

Jeśli umieścisz definicje funkcji w pliku kodu powiązanym z nagłówkiem, nie będą one wstawiane, Twój kod będzie mniejszy, może działać wolniej, ale powinieneś je skompilować tylko jeden raz. Szczegóły implementacji są ukrywane i oddzielane od użytkownika.

1

Nie ma absolutnie żadnego powodu, aby umieszczać treści funkcji w plikach nagłówkowych w "c". Jeśli plik nagłówkowy znajduje się w wielu plikach "c", zmusiłoby to kompilator do wielokrotnego zdefiniowania tej funkcji. Jeśli funkcja jest "statyczna", w programie będzie jej wiele kopii, jeśli jest ona globalna, linker złoży skargę.

Podobne rozumowanie dotyczy C++. Wyjątkiem są "inline" członkowie klasy i niektóre implementacje szablonów.

Jeśli zdefiniujesz tymczasową klasę w pliku "cpp", idealnie jest zdefiniować ją tam i zdefiniować cale funkcji zdefiniowane w klasie.

+0

Bardzo zwięzła odpowiedź. Tahnks. – SavedbyZer0