C++ error: Invalid use of incomplete type ...
Habe ich eine kleine bis mittelgroße Projekt, das Tue ich für meine software-engineering-Kurs in diesem semester. Ich habe entschieden, es zu tun in C++ (gtkmm). Ich Tue, okay so weit, aber ich habe ein problem mit zirkulären Referenzen oder die folgenden Fehler:
Login_Dialog.cpp:25: error: invalid use of incomplete type ‘struct MainWindow’
Login_Dialog.h:12: error: forward declaration of ‘struct MainWindow’
make: *** [Login_Dialog.o] Error 1
Kurz gesagt, ich habe über 10 Klassen und ich weiß, in der Zukunft werden Sie alle gehen zu müssen, um miteinander zu reden. Ich habe laufen in einem konkreten Fall so weit, und ich habe versucht, es zu beheben, auf meiner eigenen, aber ich bin völlig stecken.
Mein Programm hat ein Hauptfenster-Klasse, die wie folgt definiert ist:
/*
* MainWindow.h
*/
#ifndef MAINWINDOW_H_
#define MAINWINDOW_H_
#include "includes.h"
#include "ModelDrawing.h"
#include "ViewDrawing.h"
#include "ControlerDrawing.h"
#include "ModelChat.h"
#include "ViewChat.h"
#include "ControlerChat.h"
#include "ModelQueue.h"
#include "ViewQueue.h"
#include "ControlerQueue.h"
#include "Login_Dialog.h"
#include "TCP_IP_Socket.h"
class MainWindow : public Window
{
public:
MainWindow(int type);
~MainWindow();
void on_menu_file_new_generic();
void on_menu_file_quit();
ModelDrawing* get_mdl_Draw();
ViewDrawing* get_view_Draw();
ControlerDrawing* get_cntrl_Draw();
ModelChat* get_mdl_Chat();
ViewChat* get_view_Chat();
ControlerChat* get_cntrl_Chat();
ModelQueue* get_mdl_Que();
ViewQueue* get_view_Que();
ControlerQueue* get_cntrl_Que();
Label* get_status_label();
void set_status_label(Glib::ustring label);
TCP_IP_Socket* get_socket();
private:
TCP_IP_Socket* socket;
Widget* menu;
RefPtr<Gtk::ActionGroup> m_refActionGroup;
RefPtr<Gtk::UIManager> m_refUIManager;
ModelDrawing* mdl_Draw;
ViewDrawing* view_Draw;
ControlerDrawing* cntrl_Draw;
ModelChat* mdl_Chat;
ViewChat* view_Chat;
ControlerChat* cntrl_Chat;
ModelQueue* mdl_Que;
ViewQueue* view_Que;
ControlerQueue* cntrl_Que;
Frame* label_frame;
Label* status_label;
Login_Dialog* login;
protected:
//Containers
HBox* main_HBox;
VBox* base_VBox;
};
#endif /* MAINWINDOW_H_ */
Die Funktionen sind wie folgt definiert:
/*
* MainWindow.cpp
*/
#include "MainWindow.h"
MainWindow::MainWindow(int type)
{
this->socket = new TCP_IP_Socket(this);
//Login Section
this->login = new Login_Dialog(WINDOW_TOPLEVEL, this);
int status;
status = this->login->run();
if(status == 0)
{
exit(1);
}
this->login->hide();
//By Default Create and Open Up Student Queue
this->mdl_Que = new ModelQueue(this);
this->view_Que = new ViewQueue(this);
this->cntrl_Que = new ControlerQueue(this, (this->mdl_Que), (this->view_Que));
this->set_default_size(1200, 750);
this->set_border_width(1);
this->set_title("Tutor App");
this->base_VBox = manage(new VBox());
this->main_HBox = manage(new HBox());
this->label_frame = manage(new Frame());
m_refActionGroup = Gtk::ActionGroup::create();
m_refUIManager = Gtk::UIManager::create();
m_refActionGroup->add(Gtk::Action::create("FileMenu", "File"));
this->add_accel_group(m_refUIManager->get_accel_group());
Glib::ustring ui_info =
"<ui>"
"<menubar name='MenuBar'>"
" <menu action='FileMenu'>"
" </menu>"
"</menubar>"
"</ui>";
m_refUIManager->insert_action_group(m_refActionGroup);
m_refUIManager->add_ui_from_string(ui_info);
this->menu = m_refUIManager->get_widget("/MenuBar");
this->mdl_Draw = new ModelDrawing(this);
this->view_Draw = new ViewDrawing(this);
this->cntrl_Draw = new ControlerDrawing(this, (this->mdl_Draw), (this->view_Draw));
this->mdl_Chat = new ModelChat(this);
this->view_Chat = new ViewChat(this);
this->cntrl_Chat = new ControlerChat(this, (this->mdl_Chat), (this->view_Chat));
this->status_label = manage(new Label("Welcome to The Tutor App", ALIGN_LEFT, ALIGN_LEFT, false));
//Put it all together
this->main_HBox->pack_start(*(this->view_Draw->get_left_VBox()));
this->label_frame->add(*(this->status_label));
this->base_VBox->pack_end(*(this->label_frame));
this->main_HBox->pack_end(*(this->view_Chat->get_right_VBox()));
this->base_VBox->pack_start(*(this->menu), Gtk::PACK_SHRINK);
this->base_VBox->pack_end(*(this->main_HBox), true, true);
this->label_frame->set_size_request(-1, 5);
this->add(*(this->base_VBox));
this->show_all();
this->view_Que->get_window()->show_all();
}
MainWindow::~MainWindow()
{
}
ModelDrawing* MainWindow::get_mdl_Draw()
{
return NULL;
}
ViewDrawing* MainWindow::get_view_Draw()
{
return NULL;
}
ControlerDrawing* MainWindow::get_cntrl_Draw()
{
return NULL;
}
ModelChat* MainWindow::get_mdl_Chat()
{
return NULL;
}
ViewChat* MainWindow::get_view_Chat()
{
return NULL;
}
ControlerChat* MainWindow::get_cntrl_Chat()
{
return NULL;
}
ModelQueue* MainWindow::get_mdl_Que()
{
return NULL;
}
ViewQueue* MainWindow::get_view_Que()
{
return this->view_Que;
}
ControlerQueue* MainWindow::get_cntrl_Que()
{
return NULL;
}
Label* MainWindow::get_status_label()
{
return this->status_label;
}
void MainWindow::set_status_label(Glib::ustring label)
{
this->status_label->set_label(label);
}
TCP_IP_Socket* MainWindow::get_socket()
{
return this->socket;
}
void MainWindow::on_menu_file_quit()
{
hide(); //Closes the main window to stop the Gtk::Main::run().
}
void MainWindow::on_menu_file_new_generic()
{
std::cout << "A File|New menu item was selected." << std::endl;
}
Nun das Hauptfenster erstellt eine TCP_IP_Socket
Klasse und ein login-dialog. Ich zuerst erstellen Sie die Verbindung und legen Sie ein paar strings (gesehen im code unten):
/*
* TCP_IP_Socket.cpp
*/
#include "TCP_IP_Socket.h"
TCP_IP_Socket::TCP_IP_Socket(MainWindow* hwnd)
{
this->hwnd = hwnd;
server_name = "www.geoginfo.com";
this->set_server_ustring(this->server_name);
printf("%s", this->server_name);
struct addrinfo specs;
struct addrinfo* results;
int status;
memset(&specs, 0, sizeof specs);
specs.ai_flags = 0;
specs.ai_family = AF_UNSPEC; //AF_INET or AF_INET6 to force version
specs.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(this->server_name, NULL, &specs, &results)) != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
exit(0);
}
char ipstr[INET6_ADDRSTRLEN];
void* addr;
if (results->ai_family == AF_INET)
{ //IPv4
struct sockaddr_in* ipv4 = (struct sockaddr_in*)results->ai_addr;
addr = &(ipv4->sin_addr);
}
else
{ //IPv6
struct sockaddr_in6* ipv6 = (struct sockaddr_in6 *)results->ai_addr;
addr = &(ipv6->sin6_addr);
}
inet_ntop(results->ai_family, addr, ipstr, sizeof ipstr);
this->set_serverip_ustring(ipstr);
printf(" = %s\n", ipstr);
freeaddrinfo(results); //free the linked list
printf("\n");
}
TCP_IP_Socket::~TCP_IP_Socket()
{
}
void TCP_IP_Socket::set_server_ustring(const char* server_name)
{
this->server_domainname = new ustring(server_name);
}
void TCP_IP_Socket::set_serverip_ustring(const char* ip)
{
this->server_ip = new ustring(ip);
}
Glib::ustring* TCP_IP_Socket::get_server_domainname()
{
return this->server_domainname;
}
Glib::ustring* TCP_IP_Socket::get_server_ip()
{
return this->server_ip;
}
und dann erstelle ich den login und Zugriff auf den server_ip
ustring und server_domainname
ustring von meinem login-dialog:
/*
* Login_Dialog.cpp
*/
#include "Login_Dialog.h"
Login_Dialog::Login_Dialog(int type, MainWindow* hwnd)
{
this->hwnd = hwnd;
this->set_default_size(100, 150);
this->user_layout = manage(new HBox());
this->pswd_layout = manage(new HBox());
this->user_name = manage(new Label("Username"));
this->user_entry = manage(new Entry());
this->pswd_user = manage(new Label("Password"));
this->pswd_entry = manage(new Entry());
this->Ok = add_button("Ok", 1);
this->Cancel = add_button("Cancel", 0);
Glib::ustring* one = hwnd->get_socket()->get_server_domainname();
this->status_label = manage (new Label("This is a test", ALIGN_LEFT, ALIGN_LEFT, false));
this->Ok->set_size_request(74, -1);
this->Cancel->set_size_request(74, -1);
this->user_layout->pack_start(*(this->user_name), true, true);
this->user_layout->pack_end(*(this->user_entry), true, true);
this->pswd_layout->pack_start(*(this->pswd_user), true, true);
this->pswd_layout->pack_end(*(this->pswd_entry), true, true);
this->get_vbox()->pack_start(*(this->user_layout));
this->get_vbox()->pack_end(*(this->status_label), true, true);
this->get_vbox()->pack_end(*(this->pswd_layout));
show_all(); //<-- This is key
}
void Login_Dialog::set_status_label(Glib::ustring label)
{
this->status_label->set_label(label);
}
Wenn ich versuche zu kompilieren, dies bekomme ich die Fehlermeldung, aufgeführt an der Spitze von diesem post. Wenn ich entfernen class MainWindow;
und ersetzen Sie es mit #include "MainWindow.h"
, ich starte in Zirkelbezug Probleme mit Header.
Ich weiß, ich habe eine Menge code, aber ich wollte nicht geflamed für die Buchung nicht genug.
InformationsquelleAutor Matthew Hoggan | 2010-03-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie sich mit forward-Deklaration MainWindow in Login_Dialog.h, solange Sie sich nur nach vorne declar einen Zeiger auf den Typ (was Sie tun), und fügen Sie diese an die Spitze der
Login_Dialog.h
so weiß der compiler erwarten, um zu sehen, eine Klasse Erklärung zu einem späteren Zeitpunkt.Dann in Login_Dialog.cpp, include "mainwindow.h" wie diese.
Das sollte es tun.
InformationsquelleAutor John Knoeller
Aber das ist das Problem. Sie verschieben müssen, um die Umsetzung in eine separate Implementierung (.cpp-Datei). Sie können forward-Deklaration durchbrechen circular references im header-Dateien, aber Sie haben beide Header zur Verfügung, bevor Sie mit Ihrem Typ.
Haben Sie auch den vollständigen definition Sie Klasse, bevor Sie Sie verwenden können-nicht nur eine vorwärts-Deklaration. Forward-Deklarationen sind nur nützlich, um anderen forward-Deklarationen -- der compiler muss wissen, welche Art es ist, die Arbeit mit vor kann code generieren.
InformationsquelleAutor Billy ONeal
Den Fehler zu beheben, sollten Sie ersetzen Sie #include "Login_Dialog.h" mit vorwärts-Deklaration von Login_Dialog Klasse in Main_Window.h. Dann Login_Dialog.h in Main_Window.cpp und Main_Window.h in Login_Dialog.cpp. BTW, das gleiche getan werden kann, für viele andere Dateien/Klassen.
InformationsquelleAutor Corwin