2010-03-06 3 views
6

У меня есть проект небольшого и среднего размера, который я делаю для своего курса по разработке программного обеспечения в этом семестре. Я решил сделать это на C++ (gtkmm). Я делаю хорошо до сих пор, но я столкнулся с проблемой с циклическими ссылками или следующие ошибки:Ошибка C++: Недопустимое использование неполного типа ...

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 

Короче у меня есть около 10 классов, и я знаю, в будущем все они собираются должны поговорить друг друга. До сих пор я столкнулся с одним конкретным случаем, и я пытался решить это самостоятельно, но я полностью застрял.

Моя программа имеет основной класс окна, который определяется следующим образом:

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

функции определяются следующим образом:

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

Теперь главное окно создает TCP_IP_Socket класс и диалог входа в систему , Я сначала создать соединение и установить несколько строк (видели в коде ниже):

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

и затем я создаю логин и попытаться получить доступ к server_ip ustring и server_domainname ustring из моего диалога входа:

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

Когда я пытаюсь скомпилировать это, я получаю ошибку, указанную в самой верхней части этой записи. Если я удалю class MainWindow; и заменил его #include "MainWindow.h", я столкнулся с круглыми проблемами с заголовками.

Я знаю, что я опубликовал много кода, но я не хотел, чтобы его пламя не было достаточно для публикации.

+7

Вы опубликовали много кода, но пропустили ключевое слово. Login_Dialog.h – Naveen

ответ

15

Вы можете уйти с объявлением MainWindow в Login_Dialog.h до тех пор, пока вы только отправляете декларацию указателя на тип (который вы делаете), и вы добавляете это в начало Login_Dialog.h, чтобы компилятор знал, что ожидать см. объявление класса позже.

class MainWindow; 

Затем в Login_Dialog.cpp включите «mainwindow.h», как это.

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

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

Это должно быть сделано.

+2

+1 для гораздо более конкретного - и более простого для понимания - способа сказать, что я пытался (и не смог) сказать: 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.

Но это проблема. Вам нужно переместить реализацию в отдельный файл реализации (.cpp). Вы можете использовать форвардные объявления для разрыва круговых ссылок в заголовочных файлах, но перед тем, как попытаться использовать свой тип, вы должны иметь оба заголовка.

Вы должны включить полное определение вашего класса, прежде чем сможете его использовать, а не просто декларацию вперед. Форвардные декларации полезны только для других форвардных объявлений - компилятор должен знать, с каким типом он работает, прежде чем он сможет генерировать код.

0

Чтобы исправить ошибку, вы должны заменить #include "Login_Dialog.h" на следующее объявление класса Login_Dialog в Main_Window.h. Затем включите Login_Dialog.h в Main_Window.cpp и Main_Window.h в Login_Dialog.cpp. BTW, то же самое можно сделать и для многих других файлов/классов.

Смежные вопросы