I have a small- to medium-size project that I am doing for my software engineering course this semester. I have chosen to do it in C++ (gtkmm). I am doing okay so far but I have run into a problem with circular references or the following errors:
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
In short I have about 10 classes and I know in the future they are all going to need to talk to each other. I have run into one specific case so far, and I have been trying to resolve it on my own, but I am totally stuck.
My program has a main window class that is defined as follows:
/*
* 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_ */
The functions are defined as follows:
/*
* 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;
}
Now the main window creates a TCP_IP_Socket
class and a login dialog. I first create the connection and set a few strings (seen in the code below):
/*
* 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;
}
and then I create the login and try to access the server_ip
ustring and server_domainname
ustring from my 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);
}
When I try to compile this I get the error listed at the very top of this post. If I remove class MainWindow;
and replace it with #include "MainWindow.h"
, I run into circular reference issues with headers.
I know I posted a lot of code, but I didn't want to get flamed for not posting enough.
You can get away with forward declaring MainWindow in Login_Dialog.h as long as you only forward declar a pointer to the type (which you do), and you add this to the top of Login_Dialog.h
so the compiler knows to expect to see a class declaration at some later time.
class MainWindow;
Then in Login_Dialog.cpp, include "mainwindow.h" like this.
/*
* Login_Dialog.cpp
*
* Created on: Mar 2, 2010
* Author: Matthew
*/
#include "Login_Dialog.h"
#include "MainWindow.h"
That should do it.
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.
But this is the issue. You need to move the implementation into a separate implementation (.cpp) file. You can use forward declarations to break circular references in header files, but you have to have both headers available before you attempt to use your type.
You have to include the full definition of you class before you can use it -- not just a forward declaration. Forward declarations are only useful to other forward declarations -- the compiler needs to know what type it's working with before it can generate code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With