2010-03-06 27 views
6

Tengo un proyecto pequeño o mediano que estoy haciendo para mi curso de ingeniería de software este semestre. He elegido hacerlo en C++ (gtkmm). Estoy haciendo bien hasta ahora, pero se han topado con un problema con referencias circulares o los errores siguientes:Error de C++: uso no válido del tipo incompleto ...

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 

En resumen Tengo cerca de 10 clases y sé que en el futuro todos van a tener que hablar con El uno al otro. Hasta ahora me he topado con un caso específico, y he estado tratando de resolverlo por mi cuenta, pero estoy totalmente atascado.

Mi programa tiene una clase de ventana principal que se define como sigue:

/* 
* 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_ */ 

Las funciones se definen como sigue:

/* 
* 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; 
} 

Ahora la ventana principal crea una clase TCP_IP_Socket y un cuadro de diálogo de inicio de sesión . La primera vez que se crea la conexión y ajuste de algunos hilos (visto en el código de abajo):

/* 
* 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; 
} 

y entonces crear el inicio de sesión y tratar de acceder al server_ip ustring y server_domainname ustring de mi diálogo de entrada:

/* 
* 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); 
} 

Cuando intento compilar esto, aparece el error en la parte superior de esta publicación. Si elimino class MainWindow; y lo reemplazo por #include "MainWindow.h", me encuentro con problemas de referencia circulares con encabezados.

Sé que publiqué un montón de código, pero no quería que me llamaran por no publicar lo suficiente.

+7

Ha publicado mucho código, pero ha olvidado el crucial. Login_Dialog.h – Naveen

Respuesta

15

Puede salir adelante declarando MainWindow en Login_Dialog.h siempre y cuando solo desvíe un puntero al tipo (que lo hace), y lo agrega al principio de Login_Dialog.h para que el compilador sepa esperar ver una declaración de clase en algún momento posterior.

class MainWindow; 

Luego en Login_Dialog.cpp, incluya "mainwindow.h" de esta manera.

/* 
* Login_Dialog.cpp 
* 
* Created on: Mar 2, 2010 
*  Author: Matthew 
*/ 

#include "Login_Dialog.h" 
#include "MainWindow.h" 

Eso debería hacerlo.

+2

+1 para una forma mucho más específica (y más fácil de entender) de decir lo que estaba intentando (y no decir) decir: P –

1

When I try and do this I get the error presented at the very top of this post. If I try and remove the class MainWindow; and replace it with #include "MainWindow.h" I run into circular reference issues with headers.

Pero este es el problema. Debe mover la implementación a un archivo de implementación separado (.cpp). Puede usar las declaraciones de reenvío para romper las referencias circulares en los archivos de encabezado, pero debe tener ambos encabezados disponibles antes de intentar usar su tipo.

Debe incluir la definición completa de su clase antes de poder usarla, no solo una declaración directa. Las declaraciones directas solo son útiles para otras declaraciones directas: el compilador necesita saber con qué tipo está trabajando antes de poder generar el código.

0

Para solucionar el error, debe reemplazar #include "Login_Dialog.h" con la declaración directa de la clase Login_Dialog en Main_Window.h. A continuación, incluya Login_Dialog.h en Main_Window.cpp y Main_Window.h en Login_Dialog.cpp. Por cierto, lo mismo se puede hacer para muchos otros archivos/clases.

Cuestiones relacionadas