Mam dwie klasy zadeklarowane jak poniżej:
class User
{
public:
MyMessageBox dataMsgBox;
};
class MyMessageBox
{
public:
void sendMessage(Message *msg, User *recvr);
Message receiveMessage();
vector<Message> *dataMessageList;
};
Kiedy próbuję skompilować go za pomocą gcc, daje następujący błąd:
MyMessageBox nie nazywa typu
g++
a niegcc
Odpowiedzi:
Kiedy kompilator kompiluje klasę
User
i przechodzi doMyMessageBox
linii,MyMessageBox
nie została jeszcze zdefiniowana. Kompilator nie ma pojęcia, żeMyMessageBox
istnieje, więc nie może zrozumieć znaczenia elementu członkowskiego twojej klasy.Musisz upewnić się, że
MyMessageBox
jest zdefiniowany, zanim użyjesz go jako członka. Można to rozwiązać, odwracając kolejność definicji. Masz jednak cykliczną zależność: jeśli przejdzieszMyMessageBox
powyżejUser
, to w definicjiMyMessageBox
nazwyUser
nie zostanie zdefiniowana!Możesz tylko zadeklarować
User
; to znaczy zadeklaruj, ale nie definiuj. Podczas kompilacji typ, który jest zadeklarowany, ale nie zdefiniowany, jest nazywany niekompletnym typem . Rozważmy prostszy przykład:Deklarując do przodu
User
,MyMessageBox
nadal może tworzyć wskaźnik lub odniesienie do niego:Nie możesz tego zrobić na odwrót: jak wspomniano, członek klasy musi mieć definicję. (Powodem jest to, że kompilator musi wiedzieć, ile pamięci
User
zajmuje i wiedzieć, że musi znać rozmiar jej członków.) Gdybyś miał powiedzieć:Nie zadziała, ponieważ nie zna jeszcze rozmiaru.
Na marginesie, ta funkcja:
Prawdopodobnie nie powinien brać żadnego z nich za pomocą wskaźnika. Nie możesz wysłać wiadomości bez wiadomości, ani nie możesz wysłać wiadomości bez użytkownika, do którego można ją wysłać. Obie te sytuacje można wyrazić, przekazując null jako argument do któregokolwiek z parametrów (null to doskonale poprawna wartość wskaźnika!)
Zamiast tego użyj odwołania (prawdopodobnie const):
źródło
MyMessageBox
przyszłości wystarczyłoby. A gdybyMyMessageBox
tak też była zmienna typuUser
- czy to byłby impas?User
miałoby a,MessageBox
które miałoby aUser
, które miałoby a,MessageBox
które miałoby aUser
, które miałoby a,MessageBox
które miałoby aUser
, które miałoby a,MessageBox
które miałobyUser
...źródło
Kompilatory C ++ przetwarzają dane wejściowe raz. Każda używana klasa musi zostać zdefiniowana jako pierwsza. Używasz
MyMessageBox
zanim go zdefiniujesz. W takim przypadku możesz po prostu zamienić dwie definicje klas.źródło
MyMessageBox
maUser
typ w deklaracji metody.User
. Ważne rozróżnienie, ponieważ oznacza to, że klasa User musi być tylko zadeklarowana w tym miejscu, a nie zdefiniowana . Ale zobacz obszerny post GMan.User
typ nie został jeszcze zadeklarowany.Musisz zdefiniować MyMessageBox przed User - ponieważ użytkownik zawiera obiekt MyMessageBox według wartości (a więc kompilator powinien znać jego rozmiar).
Będziesz także musiał przekazać dalej deklarację użytkownika przed MyMessageBox - ponieważ MyMessageBox zawiera element członkowski typu User *.
źródło
A propos, gdybyś miał:
Wtedy to również zadziała, ponieważ użytkownik jest zdefiniowany w MyMessageBox jako wskaźnik
źródło
Przed użyciem musisz zadeklarować prototyp:
edycja : Zamieniono typy
źródło
W C ++ jest zawsze zalecane, abyś miał jedną klasę na plik nagłówkowy, zobacz tę dyskusję w SO [ 1 ]. Odpowiedzi GManNickG mówią, dlaczego tak się dzieje. Ale najlepszym sposobem rozwiązania tego problemu jest umieszczenie
User
klasy w jednym pliku nagłówkowym (User.h
), aMyMessageBox
klasy w innym pliku nagłówkowym (MyMessageBox.h
). NastępnieUser.h
włączaszMyMessageBox.h
iMyMessageBox.h
włączaszUser.h
. Nie zapomnij o „include gaurds” [ 2 ], aby Twój kod się pomyślnie skompilował.źródło