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

LVL 2
Roger AlcindorAsked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
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
 
Roger 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
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
Roger 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
 
Roger 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
 
Roger 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
 
Roger 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
 
Roger 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
 
Roger 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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.