Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1307
  • Last Modified:

C/C++ multiple header file declaration problem

I am using Borland C++ Builder to write an application that uses two Units (translation units) saved as Unit1.cpp and Unit2.cpp with corresponding header files Unit1.h an Unit2.h
Unit1 contains the code for class c1 and Unit2 contains the code for class c2.
The problem I have is that I need to call a public function c2->f1(c1 *) taking a parameter of type
pointer to c1 class; furthermore, the body of c2->f1(c1 *) makes reference to a public member of c1

I have a compilation error due to not being able to #include the header files in each unit such that the c1 and c2 types are defined in time.

How do I get round this wihout multiple declarations ( declaring classes in more than one header ) ?

0
alcindor
Asked:
alcindor
  • 7
  • 6
1 Solution
 
jkrCommented:
You can do that using foward declarations, e.g.
// Unit1.h

class c2; // foward declaration

class c1 {
public:

  void foo(c2* p);
};

// Unit2.h

class c1; // foward declaration

class c2 {
public:

  void foo(c1* p);
};

Open in new window

0
 
alcindorAuthor Commented:
Hello jkr,
   I am familiar with forward declarations and your suggestion does not fix the problem;

Unit2 compiles with one error:

'b' is not a member of c1 because the type is not yet defined

Unit 1 compiles with two errors

undefined structure c2
f2 is not a member of c2 because the type is not yet defined

Unit1.h ///////////////////////////////////

class c2;

//-----------------------------------------
class Tc1 : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
    c2 *c; //pointer to u2 class
public:		// User declarations
    __fastcall Tc1(TComponent* Owner);
    void f1(c2 *p);
};

Unit1.cpp/////////////////////////////////
//----------------------------------------
__fastcall Tc1::Tc1(TComponent* Owner)
    : TForm(Owner)
{
    c = new c2(); // compiler error - undefined structure c2

}
//----------------------------------------
void Tc1::f1(c2 *p)
{
    c->f2(this); // compiler error - f2 is not a member of c2 because the type is not yet defined

    return;
}
//---------------------------------------

Unit2.h //////////////////////////////////
class c1;

class c2
{
    private:

    public:
    c2();
    ~c2();
    void f2(c1 *fm);
};

Unit2.cpp ////////////////////////////////
//----------------------------------------
c2::c2()
{

}
//----------------------------------------
c2::~c2()
{
}
//----------------------------------------
void c2::f2(c1 *fm)
{
    fm->b = 1;  // compiler error - 'b' is not a member of c1 because the type is not yet defined

}
//----------------------------------------

Open in new window

0
 
jkrCommented:
Well, in the .cpp file, you do need the actual declaration -- and there you can include both files, preferrably protected with header guards (http://en.wikipedia.org/wiki/Include_guard), e.g.
// Unit1.h
#ifndef UNIT1_H
#define UNIT1_H
class c2; // foward declaration

class c1 {
public:

  void foo(c2* p);
};
#endif

// Unit2.h
#ifndef UNIT2_H
#define UNIT2_H
class c1; // foward declaration

class c2 {
public:

  void foo(c1* p);
};
#endif

// Unit1.cpp
#include "Unit1.h"
#include "Unit2.h"

// ...

Open in new window

0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
alcindorAuthor Commented:
I have added the include guard (Sentinels) and included both header files in each unit and the same errors persist. I have also tried changing the order in which the header files are declared, still the same errors ?
0
 
jkrCommented:
You are including both header files in Unit1.cpp, are you? (Just to be sure)
0
 
alcindorAuthor Commented:
Yes, please find attached the complete code.
Unit2 now compiles without error due to a prior typeing error.
The same compiler errors persist for unit 1 however.

Unit1.h ////////////////////////////////////////
//----------------------------------------------
#ifndef Unit1H
#define Unit1H
//----------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>

class c2;

//----------------------------------------------
class Tc1 : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
    c2 *c; //pointer to c2 class
public:		// User declarations
    __fastcall Tc1(TComponent* Owner);
    void f1(c2 *p);
};
//----------------------------------------------
extern PACKAGE Tc1 *c1;
//----------------------------------------------
#endif

Unit1.cpp ///////////////////////////////////////
//-----------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit2.h"
#include "Unit1.h"

//-----------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tc1 *c1;
//-----------------------------------------------
__fastcall Tc1::Tc1(TComponent* Owner)
    : TForm(Owner)
{
    c = new c2();
}
//-----------------------------------------------
void Tc1::f1(c2 *p)
{
    c->f2(this);
    return;
}
//-----------------------------------------------

Unit2.h /////////////////////////////////////////
//-----------------------------------------------
#ifndef Unit2H
#define Unit2H

//class Tc1;

typedef class c2
{
    private:

    public:
    c2();
    ~c2();
    void f2(Tc1 *fm);
}c2;
//-----------------------------------------------
#endif

Unit2.cpp ///////////////////////////////////////
//-----------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"

//------------------------------------------------
c2::c2()
{

}
//------------------------------------------------
c2::~c2()
{
}
//------------------------------------------------
void c2::f2(Tc1 *fm)
{
    fm->b = 1;  // set caller's data (as an example)
}
//------------------------------------------------

Open in new window

0
 
jkrCommented:
Sorry, confusoin on my side - are the actual class names 'c1' and 'c2' or 'Tc1' and 'Tc2'?
0
 
alcindorAuthor Commented:
The classes are Tc1 in Unit1 and c2 in Unit2. (I know it's not consistent)
0
 
jkrCommented:
Hm, I see that you commented out the foward declaration in Unit2.h - does it work if you remove the comment slashes?
0
 
alcindorAuthor Commented:
If I don't  comment out the forward declaration in unit 2 then I get a compiler error - Multiple declaration for Tc1
0
 
jkrCommented:
Weird - if I comment out

fm->b = 1;  // set caller's data (as an example)

it compiles, otherwise not, since Tc1 has no member 'b'...
0
 
alcindorAuthor Commented:
Unit 2 compiles ok for me, without the foward declaration but including both header files in the unit2.cpp module in the following order

#include "Unit1.h"
#include "Unit2.h"

I am using Borland C++ Builder 5 Enterprise edition


0
 
alcindorAuthor Commented:
I started again from scratch, this time all is ok ?
I don't need the forward declaration in ubit1.h as I am declaring unit2.h before unit1.h in unit1.cpp

Thanks for your comments,

Roger
// UNIT1.h /////////////////////////
//--------------------------------------
#ifndef Unit1H
#define Unit1H
//--------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>

//--------------------------------------
class Tc1 : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
    c2 *c;
public:		// User declarations
    int b;
    __fastcall Tc1(TComponent* Owner);
    __fastcall ~Tc1();
};
//--------------------------------------
extern PACKAGE Tc1 *c1;
//--------------------------------------
#endif

// UNIT1.cpp ////////////////////
#include <vcl.h>
#pragma hdrstop

#include "Unit2.h"
#include "Unit1.h"
//--------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tc1 *c1;
//--------------------------------------
__fastcall Tc1::Tc1(TComponent* Owner)
    : TForm(Owner)
{
    c = new c2();
    c->f2(this);// test the function
}
//--------------------------------------
__fastcall Tc1::~Tc1()
{
    delete c;
}
//--------------------------------------

// UNIT2.h /////////////////////////
#ifndef Unit2H
#define Unit2H

class Tc1;

class c2
{
  private:

  public:
  c2();
  void f2(Tc1 *fm);
};

//--------------------------------------
#endif

// UNIT2.cpp //////////////////////
#include <vcl.h>
#pragma hdrstop

#include "Unit2.h"
#include "Unit1.h"

//--------------------------------------
c2::c2()
{

}
//--------------------------------------
void c2::f2(Tc1 *fm)
{
    fm->b = 1;
}
//--------------------------------------
#pragma package(smart_init)

Open in new window

0

Featured Post

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

  • 7
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now