Czas na myślenie - dlaczego mimo to chcesz podzielić swój plik?
Jak sugeruje tytuł, moim największym problemem są błędy linkera definicji. Naprawiłem problem, ale nie naprawiłem problemu we właściwy sposób. Przed rozpoczęciem chcę omówić powody podziału pliku klasy na wiele plików. Starałem się umieścić tutaj wszystkie możliwe scenariusze - jeśli przegapiłem którekolwiek z nich, proszę przypomnieć mi i mogę wprowadzić zmiany. Mam nadzieję, że naśladują poprawne:Oddzielając kod klasy C++ na wiele plików, jakie są zasady?
Powód 1Aby zaoszczędzić miejsce:
Masz plik zawierający deklarację klasy ze wszystkich członków klasy. Umieszczasz #include guards wokół tego pliku (lub #pragma raz), aby uniknąć konfliktów, jeśli #include plik w dwóch różnych plikach nagłówkowych, które są następnie zawarte w pliku źródłowym. Kompilujesz oddzielny plik źródłowy wraz z implementacją dowolnych metod zadeklarowanych w tej klasie, ponieważ wyłącza on ładowanie wielu linii kodu z pliku źródłowego, co nieco oczyszcza i wprowadza porządek do twojego programu.
Przykład: Jak widać, poniższy przykład można poprawić, dzieląc implementację metod klasy na inny plik. (Plik .cpp)
// my_class.hpp
#pragma once
class my_class
{
public:
void my_function()
{
// LOTS OF CODE
// CONFUSING TO DEBUG
// LOTS OF CODE
// DISORGANIZED AND DISTRACTING
// LOTS OF CODE
// LOOKS HORRIBLE
// LOTS OF CODE
// VERY MESSY
// LOTS OF CODE
}
// MANY OTHER METHODS
// MEANS VERY LARGE FILE WITH LOTS OF LINES OF CODE
}
Powód 2Aby uniknąć wielu błędów definicja linkera:
Być może to jest główny powód, dla którego chcesz podzielić realizację od deklaracji. W powyższym przykładzie możesz przenieść ciało metody na zewnątrz klasy. To sprawi, że będzie wyglądał o wiele czystszy i uporządkowany. Jednakże, zgodnie z tym question, powyższy przykład ma domyślne specyfikatory inline
. Przeniesienie implementacji z klasy na zewnątrz klasy, jak w poniższym przykładzie, spowoduje błędy linkera, a więc wstawisz wszystko lub przeniesiesz definicje funkcji do pliku .cpp.
Przykład: _ Poniższy przykład spowoduje "błędy linkera definicji wielokrotnej", jeśli nie przeniesiesz definicji funkcji do pliku .cpp lub nie określisz funkcji jako wbudowanej.
// my_class.hpp
void my_class::my_function()
{
// ERROR! MULTIPLE DEFINITION OF my_class::my_function
// This error only occurs if you #include the file containing this code
// in two or more separate source (compiled, .cpp) files.
}
Aby rozwiązać ten problem:
//my_class.cpp
void my_class::my_function()
{
// Now in a .cpp file, so no multiple definition error
}
czyli
// my_class.hpp
inline void my_class::my_function()
{
// Specified function as inline, so okay - note: back in header file!
// The very first example has an implicit `inline` specifier
}
Powód 3chcesz zaoszczędzić miejsce, ponownie, ale tym razem pracujemy z klasa szablonu:
Jeśli pracujemy z klasami szablonów, nie możemy przenieść implementacji do pliku źródłowego (plik .cpp). Obecnie nie jest to dozwolone przez (domyślam się) ani standardowy, ani bieżący kompilator. W przeciwieństwie do pierwszego przykładu z Reason 2, powyżej, możemy umieścić implementację w pliku nagłówkowym.Zgodnie z tym question powodem jest, że metody klasy szablonów mają również domyślne specyfikatory inline
. Czy to jest poprawne? (Wydaje się, że to ma sens). Ale nikt nie zdawał sobie sprawy z tego, o czym wspomniałem!
Czy oba poniższe przykłady są identyczne?
// some_header_file.hpp
#pragma once
// template class declaration goes here
class some_class
{
// Some code
};
// Example 1: NO INLINE SPECIFIER
template<typename T>
void some_class::class_method()
{
// Some code
}
// Example 2: INLINE specifier used
template<typename T>
inline void some_class::class_method()
{
// Some code
}
Jeśli masz plik nagłówkowy klasy szablon, który staje się ogromne ze względu na wszystkie funkcje tak, to wierzę, że mogą poruszać się definicje funkcji do innego pliku nagłówka (zwykle pliku .tpp?), a następnie #include file.tpp
na końcu pliku nagłówkowego zawierającego deklarację klasy. NIE wolno dołączać tego pliku w żadnym innym miejscu, w związku z czym .tpp
zamiast .hpp
.
Zakładam, że można to również zrobić za pomocą metod liniowych zwykłej klasy? Czy to też jest dozwolone?
Tura pytań
Więc zrobiłem kilka wypowiedzi powyżej, które w większości odnoszą się do struktury plików źródłowych. Myślę, że wszystko, co powiedziałem, było poprawne, ponieważ przeprowadziłem kilka podstawowych badań i "odkryłem pewne rzeczy", ale to jest pytanie, więc nie wiem na pewno.
To wszystko sprowadza się do sposobu porządkowania kodu w plikach. Myślę, że wymyśliłem strukturę, która zawsze będzie działać.
Oto, co wymyśliłem. (Jest to „kod klasy organizacja plik/struktura standardowy Eda Ptasie”, jeśli chcesz Nie wiem, czy to będzie bardzo przydatny jeszcze, że jest sens pytać..)
- 1: Zadeklaruj klasę (szablon lub inną) w pliku
.hpp
, w tym wszystkie metody, funkcje przyjaciół i dane. - 2: Na dole pliku
.hpp
,#include
plik.tpp
zawierający wdrażanie wszelkichinline
metod. Utwórz plik.tpp
i upewnij się, że wszystkie metody zostały określone jakoinline
. - 3: wszystkich pozostałych członków (funkcje non-inline, funkcje przyjaciel i danych statycznych) powinny być zdefiniowane w pliku
.cpp
, który#include
s plik.hpp
na górze, aby uniknąć błędów takich jak „klasa ABC nie została uznana ". Ponieważ wszystko w tym pliku będzie miało zewnętrzne powiązanie, program połączy poprawnie.
Czy standardy takie istnieją w przemyśle? Czy standard wymyślił pracę we wszystkich przypadkach?
Przy okazji przeszedłem twoje pytanie, ponieważ było zbyt długie. Informacje o wbudowanej funkcji szablonu. Słowo kluczowe wbudowane nie jest wymagane (nadal można umieszczać je w plikach nagłówkowych) i nie ma żadnego gwarantowanego efektu. Używanie słowa kluczowego może sprawić, że kompilator będzie bardziej skłonny do wstawienia funkcji, ale nic nie jest pewne. Te funkcje szablonu nie są niejawnie wbudowanymi funkcjami. Odpowiedź na to pytanie jest błędna, co omówiono w odpowiedziach na uwagi. –
@NeilKirk Ah dzięki, pewności wydawało się być dużo niezgody na ten temat. – user3728501
Po prostu zignoruj wstawianie tam, a problem nigdy ci nie przeszkodzi :) –