简体   繁体   English

C ++错误:使用不完整类型无效...

[英]C++ error: Invalid use of incomplete type …

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). 我选择用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. 总之,我有大约10个班级,我知道将来他们都需要互相交谈。 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. 现在主窗口创建一个TCP_IP_Socket类和一个登录对话框。 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: 然后我创建登录并尝试从我的登录对话框中访问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);
}

When I try to compile this I get the error listed at the very top of this post. 当我尝试编译这个时,我得到了这篇文章最上面列出的错误。 If I remove class MainWindow; 如果我删除class MainWindow; and replace it with #include "MainWindow.h" , I run into circular reference issues with headers. 并用#include "MainWindow.h"替换它,我遇到了标题的循环引用问题。

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. 只要您只转发声明指向该类型的指针(您这样做),就可以在Login_Dialog.h中声明前向声明MainWindow,然后将其添加到Login_Dialog.h的顶部,以便编译器知道期望看到以后的类声明。

class MainWindow;

Then in Login_Dialog.cpp, include "mainwindow.h" like this. 然后在Login_Dialog.cpp中,像这样包含“mainwindow.h”。

/*
 * 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; 如果我尝试删除MainWindow类; and replace it with #include "MainWindow.h" I run into circular reference issues with headers. 并用#include“MainWindow.h”替换它。我遇到了标题的循环引用问题。

But this is the issue. 但这是问题所在。 You need to move the implementation into a separate implementation (.cpp) file. 您需要将实现移动到单独的实现(.cpp)文件中。 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. 前向声明仅对其他前向声明有用 - 编译器需要知道它在生成代码之前使用的类型。

To fix the error you should replace #include "Login_Dialog.h" with forward declaration of Login_Dialog class in Main_Window.h. 要修复错误,您应该将#include“Login_Dialog.h”替换为Main_Window.h中的Login_Dialog类的前向声明。 Then include Login_Dialog.h in Main_Window.cpp and Main_Window.h in Login_Dialog.cpp. 然后在Main_Window.cpp中包含Login_Dialog.h,在Login_Dialog.cpp中包含Main_Window.h。 BTW, the same can be done for many other files/classes. 顺便说一句,对许多其他文件/类也可以这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM