Link to home
Start Free TrialLog in
Avatar of Roger Alcindor
Roger Alcindor

asked on

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 ) ?

ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Roger Alcindor
Roger Alcindor

ASKER

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

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

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 ?
You are including both header files in Unit1.cpp, are you? (Just to be sure)
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

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


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