C++ 前向声明和“不允许不完整类型”错误

问题描述 投票:0回答:1

我有两个类(或者更好的是头文件)是我的 C++ 程序的一部分,但我根本无法让这一切正常工作!作为我的应用程序的一部分,他们基本上需要彼此的数据才能正常运行。

不要通过阅读这段代码来折磨自己;我只需要解决前向声明相互包含问题,因此只需查看代码中与此问题相关的部分即可。

错误发生在第二个代码片段的最后(我不得不从第一个代码片段中删除一大块代码,所以我可以发布问题,我想这与我的问题无关)。

introForm.h

#pragma once
#include <stdlib.h>
#include "creditsForm.h"
#include "registerForm.h"
#include "aboutForm.h"
#include "QuizForm.h"
#include <windows.h>
#include <time.h>
#ifndef __introForm__H__
#define __introForm__H__

namespace InteractiveQuiz {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    ref class QuizForm;

    /// <summary>
    /// Summary for introForm
    /// </summary>
    public ref class introForm : public System::Windows::Forms::Form
    {
    public:
        introForm(void)
        {
            InitializeComponent();
            //
            //TODO: Add the constructor code here
            //
        }
        
    protected:
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        ~introForm()
        {
            if (components)
            {
                delete components;
            }
        }
    
        // Extracts a word from a sentence with a given ordinal number
        string extractWord(int ordinal, string sentence)
        {
            int counter = 0;
            string word;

            for (int i = 0; i < sentence.length(); i++)
            {
                if (sentence[i] == ',')
                {
                    if (sentence [i+1] != ',')
                    {
                        counter ++;

                        if (counter == ordinal)
                        {
                            return word;
                        }

                        word ="";
                    }
                }
                else
                {
                    word += sentence[i];
                }       
            }
        }

private: System::Void btnExit1_Click(System::Object^  sender, System::EventArgs^  e) {
             exit(1);
         }
private: System::Void btnCredits1_Click(System::Object^  sender, System::EventArgs^  e) {
             creditsForm^ credits = gcnew creditsForm;
             credits->Show();
         }
private: System::Void registerBtn_Click(System::Object^  sender, System::EventArgs^  e) {
             registerForm^ registerUser = gcnew registerForm;
             registerUser->Show();
         }
private: System::Void aboutToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
             aboutForm^ aboutApp = gcnew aboutForm;
             aboutApp->Show();
         }
private: System::Void quitToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
             introForm::Close();
         }
private: System::Void introForm_Load(System::Object^  sender, System::EventArgs^  e) {
             ifstream regUsers ("regUsers.csv");

             if (regUsers)
             {
                 lblUser->Enabled = true;
                 lblPass->Enabled = true;

                 logUsername->Enabled = true;
                 logPassword->Enabled = true;

                 btnLogSubmit->Enabled = true;
                 if (lblLogin->Text == L"Not logged in")
                 {
                    quizLogo->Visible = false;
                 }
             }
             else
             {
                 lblUser->Enabled = false;
                 lblPass->Enabled = false;

                 logUsername->Enabled = false;
                 logPassword->Enabled = false;

                 btnLogSubmit->Enabled = false;

                 quizLogo->Visible = true;
             }

             regUsers.close();
         }

public: String^ loggedUser;

private: System::Void btnLogSubmit_Click(System::Object^  sender, System::EventArgs^  e) {
             if (logUsername->Text->Length < 6 && logPassword->Text->Length < 8)
             {
                 errorLabel->Text = L"Username must be at least 6 and password 8 characters long!";
                 errorLabel->Visible = true;
             }
             else if (logUsername->Text->Length < 6)
             {
                 errorLabel->Text = L"Username must be at least 6 characters long!";
                 errorLabel->Visible = true;
             }
             else if (logUsername->Text->Contains(" "))
             {
                 errorLabel->Text = L"Username must not contain spaces!";
                 errorLabel->Visible = true;
             }
             else if (logPassword->Text->Length < 8)
             {
                 errorLabel->Text = L"Password must be at least 8 characters long!";
                 errorLabel->Visible = true;
             }
             if (logUsername->Text->Length >= 6 && logPassword->Text->Length >= 8)
             {
                 String^ result = logUsername->Text + "," + logPassword->Text;
                 string result2 = marshal_as<string>(result);

                 ifstream regUsers("regUsers.csv");
                 string line;
                 string fileUserPass;

                 /* While there is still a line. */
                 while(getline(regUsers, line))
                 {
                     fileUserPass = extractWord(1, line) + "," + extractWord(2,line);

                     if (fileUserPass == result2) // Successful login
                     {
                         lblLogin->Text = L"Logged in as " + logUsername->Text;

                         quizLogo->Visible = true;
                         errorLabel->Visible = false;

                         btnLogout->Enabled = true;

                         startNewToolStripMenuItem->Enabled = true;

                         loggedUser = logUsername->Text;
                     } 
                 }

                 regUsers.close();

                 if (fileUserPass != result2)
                 {
                     errorLabel->Text = L"Username or password incorrect!";
                     errorLabel->Visible = true;
                 }
             }
         }
private: System::Void btnLogout_Click(System::Object^  sender, System::EventArgs^  e) {
             btnLogout->Enabled = false;

             lblLogin->Text = L"Not logged in";

             quizLogo->Visible = false;

             errorLabel->Visible = false;

             logUsername->Clear();
             logPassword->Clear();

             logUsername->Focus();

             startNewToolStripMenuItem->Enabled = false;
         }
private: System::Void startNewToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
             QuizForm^ quiz = gcnew QuizForm;
             quiz->Show();
         }
};
}

#endif // !__introForm__H__

测验表格.h

#pragma once
#include <string.h>
using namespace std;

#ifndef __QuizForm__H__
#define __QuizForm__H__

namespace InteractiveQuiz {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    
    ref class introForm;

    /// <summary>
    /// Summary for QuizForm
    /// </summary>
    public ref class QuizForm : public System::Windows::Forms::Form
    {
    public:
        QuizForm(void)
        {
            InitializeComponent();
            //
            //TODO: Add the constructor code here
            //
        }


    protected:
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        ~QuizForm()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::TabControl^  tabControl;
    protected: 

    protected: 
    private: System::Windows::Forms::TabPage^  tabPage1;
    private: System::Windows::Forms::TabPage^  tabPage2;
    private: System::Windows::Forms::MenuStrip^  menuStrip1;
    private: System::Windows::Forms::Button^  button1;
    private: System::Windows::Forms::ToolStripMenuItem^  quizToolStripMenuItem;
    private: System::Windows::Forms::ToolStripMenuItem^  startNewToolStripMenuItem;
    private: System::Windows::Forms::ToolStripMenuItem^  endQuizToolStripMenuItem;
    private: System::Windows::Forms::ToolStripSeparator^  toolStripSeparator1;
    private: System::Windows::Forms::ToolStripMenuItem^  quitToolStripMenuItem;
    private: System::Windows::Forms::ToolStripMenuItem^  helpToolStripMenuItem;
    private: System::Windows::Forms::ToolStripMenuItem^  aboutToolStripMenuItem;
    private: System::Windows::Forms::Label^  lblQuizLogin;


    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            this->tabControl = (gcnew System::Windows::Forms::TabControl());
            this->tabPage1 = (gcnew System::Windows::Forms::TabPage());
            this->tabPage2 = (gcnew System::Windows::Forms::TabPage());
            this->menuStrip1 = (gcnew System::Windows::Forms::MenuStrip());
            this->quizToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->startNewToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->endQuizToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->toolStripSeparator1 = (gcnew System::Windows::Forms::ToolStripSeparator());
            this->quitToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->helpToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->aboutToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->button1 = (gcnew System::Windows::Forms::Button());
            this->lblQuizLogin = (gcnew System::Windows::Forms::Label());
            this->tabControl->SuspendLayout();
            this->menuStrip1->SuspendLayout();
            this->SuspendLayout();
            // 
            // tabControl
            // 
            this->tabControl->Controls->Add(this->tabPage1);
            this->tabControl->Controls->Add(this->tabPage2);
            this->tabControl->Location = System::Drawing::Point(12, 27);
            this->tabControl->Name = L"tabControl";
            this->tabControl->SelectedIndex = 0;
            this->tabControl->Size = System::Drawing::Size(686, 430);
            this->tabControl->TabIndex = 0;
            // 
            // tabPage1
            // 
            this->tabPage1->Location = System::Drawing::Point(4, 22);
            this->tabPage1->Name = L"tabPage1";
            this->tabPage1->Padding = System::Windows::Forms::Padding(3);
            this->tabPage1->Size = System::Drawing::Size(678, 404);
            this->tabPage1->TabIndex = 0;
            this->tabPage1->Text = L"tabPage1";
            this->tabPage1->UseVisualStyleBackColor = true;
            // 
            // tabPage2
            // 
            this->tabPage2->Location = System::Drawing::Point(4, 22);
            this->tabPage2->Name = L"tabPage2";
            this->tabPage2->Padding = System::Windows::Forms::Padding(3);
            this->tabPage2->Size = System::Drawing::Size(678, 404);
            this->tabPage2->TabIndex = 1;
            this->tabPage2->Text = L"tabPage2";
            this->tabPage2->UseVisualStyleBackColor = true;
            // 
            // menuStrip1
            // 
            this->menuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(2) {this->quizToolStripMenuItem, 
                this->helpToolStripMenuItem});
            this->menuStrip1->Location = System::Drawing::Point(0, 0);
            this->menuStrip1->Name = L"menuStrip1";
            this->menuStrip1->Size = System::Drawing::Size(710, 24);
            this->menuStrip1->TabIndex = 1;
            this->menuStrip1->Text = L"menuStrip1";
            // 
            // quizToolStripMenuItem
            // 
            this->quizToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(4) {this->startNewToolStripMenuItem, 
                this->endQuizToolStripMenuItem, this->toolStripSeparator1, this->quitToolStripMenuItem});
            this->quizToolStripMenuItem->Name = L"quizToolStripMenuItem";
            this->quizToolStripMenuItem->Size = System::Drawing::Size(43, 20);
            this->quizToolStripMenuItem->Text = L"&Quiz";
            // 
            // startNewToolStripMenuItem
            // 
            this->startNewToolStripMenuItem->Name = L"startNewToolStripMenuItem";
            this->startNewToolStripMenuItem->Size = System::Drawing::Size(125, 22);
            this->startNewToolStripMenuItem->Text = L"Start &New";
            // 
            // endQuizToolStripMenuItem
            // 
            this->endQuizToolStripMenuItem->Name = L"endQuizToolStripMenuItem";
            this->endQuizToolStripMenuItem->Size = System::Drawing::Size(125, 22);
            this->endQuizToolStripMenuItem->Text = L"&End Quiz";
            // 
            // toolStripSeparator1
            // 
            this->toolStripSeparator1->Name = L"toolStripSeparator1";
            this->toolStripSeparator1->Size = System::Drawing::Size(122, 6);
            // 
            // quitToolStripMenuItem
            // 
            this->quitToolStripMenuItem->Name = L"quitToolStripMenuItem";
            this->quitToolStripMenuItem->Size = System::Drawing::Size(125, 22);
            this->quitToolStripMenuItem->Text = L"Q&uit";
            // 
            // helpToolStripMenuItem
            // 
            this->helpToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(1) {this->aboutToolStripMenuItem});
            this->helpToolStripMenuItem->Name = L"helpToolStripMenuItem";
            this->helpToolStripMenuItem->Size = System::Drawing::Size(44, 20);
            this->helpToolStripMenuItem->Text = L"&Help";
            // 
            // aboutToolStripMenuItem
            // 
            this->aboutToolStripMenuItem->Name = L"aboutToolStripMenuItem";
            this->aboutToolStripMenuItem->Size = System::Drawing::Size(116, 22);
            this->aboutToolStripMenuItem->Text = L"&About...";
            // 
            // button1
            // 
            this->button1->Location = System::Drawing::Point(623, 476);
            this->button1->Name = L"button1";
            this->button1->Size = System::Drawing::Size(75, 23);
            this->button1->TabIndex = 2;
            this->button1->Text = L"Close";
            this->button1->UseVisualStyleBackColor = true;
            // 
            // lblQuizLogin
            // 
            this->lblQuizLogin->AutoSize = true;
            this->lblQuizLogin->Location = System::Drawing::Point(12, 489);
            this->lblQuizLogin->Name = L"lblQuizLogin";
            this->lblQuizLogin->Size = System::Drawing::Size(70, 13);
            this->lblQuizLogin->TabIndex = 3;
            this->lblQuizLogin->Text = L"Not logged in";
            // 
            // QuizForm
            // 
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(710, 511);
            this->Controls->Add(this->lblQuizLogin);
            this->Controls->Add(this->button1);
            this->Controls->Add(this->tabControl);
            this->Controls->Add(this->menuStrip1);
            this->MainMenuStrip = this->menuStrip1;
            this->MaximizeBox = false;
            this->MinimizeBox = false;
            this->Name = L"QuizForm";
            this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
            this->Text = L"Interactive Quiz";
            this->Load += gcnew System::EventHandler(this, &QuizForm::QuizForm_Load);
            this->tabControl->ResumeLayout(false);
            this->menuStrip1->ResumeLayout(false);
            this->menuStrip1->PerformLayout();
            this->ResumeLayout(false);
            this->PerformLayout();

        }
#pragma endregion

private: System::Void QuizForm_Load(System::Object^  sender, System::EventArgs^  e) {
             introForm^ intro = gcnew introForm; // the second introForm in this line is underlined with the mentioned error
         }
    };
}

#endif // !__QuizForm__H__

您在这两段代码中看到的是我在网上找到的拼图块。

我的目标:能够在

introForm
内部使用
QuizForm
中的变量。

c++ c++-cli declaration forward incomplete-type
1个回答
35
投票

在 C++ 中使用对象的前向声明时,请记住一些事项。

  • 您无法分配不完整的类型,因为编译器还不知道它有多大。仅使用指向不完整类型的指针即可解决此问题。
  • 在编译器看到不完整类型的定义之前,您无法引用它的成员。通过将接口和实现分离到头文件和代码文件中可以解决此问题。
  • 如果您必须使用不完整的类型,那么您可能做错了什么。尽可能避免循环引用。

关于您的评论:

当你有一个类的前向声明时,如

class foo;
,它被称为不完整类型,因为定义尚不存在。您可以通过指针间接引用它,例如
foo *bar;
,但是您不能在任何需要了解其内部结构的操作中使用它,例如取消引用它、使用它包含的函数等。您可以进行完整的声明类的一部分,尽管使用函数原型而不是函数。然后您可以在另一个文件中定义函数。这将允许您完全定义循环依赖,而不会造成任何破坏。 例如:

在键盘上包含内联标题。

各个文件:

foo.h:

#ifndef __FOO_H_INCLUDE
    #define __FOO_H_INCLUDE
    #ifndef __FOO_H_DEFINED
        #define __FOO_H_DEFINED
        class foo;
        #include "bar.h"
    #endif
    class foo{
        bar *a;
        int b;
        public:
        foo( int _b );
        bar& getbar();
        int getb();
        void setbar( bar* _a );
    };
#endif

bar.h:

#ifndef __BAR_H_INCLUDE
    #define __BAR_H_INCLUDE
    #ifndef __BAR_H_DEFINED
        #define __BAR_H_DEFINED
        class bar;
        #include "foo.h"
    #endif
    class bar{
        foo *a;
        int b;
        public:
        bar(int _b );
        foo& getfoo();
        int getb();
        void setfoo( foo* _a );
    };
#endif

main.cpp:

#include<iostream>
#include "foo.h"
#include "bar.h"

foo::foo( int _b ){ b = _b;}
int foo::getb(){ return b; }
bar& foo::getbar(){ return *a; }
void foo::setbar( bar* _a){ a = _a; }

bar::bar( int _b ){ b = _b;}
int bar::getb(){ return b; }
foo& bar::getfoo(){ return *a; }
void bar::setfoo( foo* _a ){ a = _a; }



int main(){
    foo a(5);
    bar b(20);
    a.setbar(&b);
    b.setfoo(&a);
    std::cout   << a.getbar().getfoo().getbar().getb() 
                << "\n" 
                << a.getbar().getfoo().getbar().getfoo().getb();
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.