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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2391401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:16:43  来源:igfitidea点击:

C++ error: Invalid use of incomplete type ...

c++

提问by Matthew Hoggan

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:

本学期我正在为我的软件工程课程做一个中小型项目。我选择用 C++ (gtkmm) 来做。到目前为止我做得还不错,但我遇到了循环引用问题或以下错误:

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.

简而言之,我有大约 10 个班级,我知道将来他们都需要相互交谈。到目前为止,我遇到了一个特定的案例,我一直在尝试自己解决它,但我完全被卡住了。

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_Socketclass and a login dialog. I first create the connection and set a few strings (seen in the code below):

现在主窗口创建一个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;
}

and then I create the login and try to access the server_ipustring and server_domainnameustring from my login dialog:

然后我创建登录并尝试从我的登录对话框访问server_ipustring 和server_domainnameustring:

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

当我尝试编译它时,我得到了这篇文章最顶部列出的错误。如果我将class MainWindow;其删除并替换为 ,则会#include "MainWindow.h"遇到标题的循环引用问题。

I know I posted a lot of code, but I didn't want to get flamed for not posting enough.

我知道我发布了很多代码,但我不想因为发布得不够多而受到抨击。

回答by John Knoeller

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.hso 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.

那应该这样做。

回答by Billy ONeal

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.

当我尝试这样做时,我收到了这篇文章顶部显示的错误。如果我尝试删除类 MainWindow; 并将其替换为 #include "MainWindow.h" 我遇到了标题的循环引用问题。

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.

但这就是问题所在。您需要将实现移动到单独的实现 (.cpp) 文件中。您可以使用前向声明来中断头文件中的循环引用,但在尝试使用您的类型之前,您必须让两个头文件都可用。

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.

在使用它之前,您必须包含类的完整定义——而不仅仅是前向声明。前向声明只对其他前向声明有用——编译器在生成代码之前需要知道它正在使用什么类型。

回答by Corwin

To fix the error you should replace #include "Login_Dialog.h" with forward declaration of Login_Dialog class in Main_Window.h. Then include Login_Dialog.h in Main_Window.cpp and Main_Window.h in Login_Dialog.cpp. BTW, the same can be done for many other files/classes.

要修复该错误,您应该将 #include "Login_Dialog.h" 替换为 Main_Window.h 中 Login_Dialog 类的前向声明。然后在 Main_Window.cpp 中包含 Login_Dialog.h,在 Login_Dialog.cpp 中包含 Main_Window.h。顺便说一句,对于许多其他文件/类也可以这样做。