I have two classes (or better yet, header files) that are part of my C++ program and I simply can't make this all work! They basically need each other's data in order to function properly, as part of my app.
Don't torture yourself by reading the meat of this code; I just need the forward declaration and mutual inclusion problem resolved, so only take a look at those parts of the code which matter for this problem.
The error occurs in the second code snippet, at the very end (I had to chop off a huge chunk of code from the first snippet, so I could post the question, I guess it's irrelevant to my problem).
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__
QuizForm.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__
What you see in these 2 pieces of code is something I constructed as puzzle pieces I found throughout the net, haha. :)
My goal: to be able to use a variable from introForm inside QuizForm.
Thanks in advance! Boris J.
To solve this, you can forward-declare the parts you need in one of the files and leave the #include out of that file. Hmm... the declaration of Car is required here as Wheel has a pointer to a Car , but Car. h can't be included here as it would result in a compiler error.
This is because a definition of a struct is not an implementation. C compiler needs this information in order to process declarations of the struct correctly. A forward declaration lets you define a pointer to your struct ; declaring a struct itself requires a full definition.
An incomplete type is a type that describes an identifier but lacks information needed to determine the size of the identifier. An incomplete type can be: A structure type whose members you have not yet specified. A union type whose members you have not yet specified.
A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier. In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function's body.
When using forward declarations of objects in C++, keep a few things in mind.
In regards to your comment:
When you have a forward declaration of a class, like class foo;
, it's called an incomplete type, as the definition doesn't exist yet. You can refer to it indirectly via pointers, like foo *bar;
, but you can't use it in any operations that require knowledge of its internals, such as dereferencing it, using functions that it contains, etc. You can make a full declaration of a class, though using function prototypes instead of functions. You can then define the functions in another file. This will allow you to completely define a circular dependency without making anything blow up.
For example:
On codepad with the headers inline-included.
The individual files:
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;
}
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