Solved

C/C++ multiple header file declaration problem

Posted on 2011-02-19
13
1,293 Views
Last Modified: 2012-05-11
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
Comment
Question by:alcindor
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 6
13 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 34934105
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
 
LVL 2

Author Comment

by:alcindor
ID: 34934333
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
 
LVL 86

Expert Comment

by:jkr
ID: 34934367
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Author Comment

by:alcindor
ID: 34934416
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
 
LVL 86

Expert Comment

by:jkr
ID: 34934507
You are including both header files in Unit1.cpp, are you? (Just to be sure)
0
 
LVL 2

Author Comment

by:alcindor
ID: 34934643
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
 
LVL 86

Expert Comment

by:jkr
ID: 34934692
Sorry, confusoin on my side - are the actual class names 'c1' and 'c2' or 'Tc1' and 'Tc2'?
0
 
LVL 2

Author Comment

by:alcindor
ID: 34934704
The classes are Tc1 in Unit1 and c2 in Unit2. (I know it's not consistent)
0
 
LVL 86

Expert Comment

by:jkr
ID: 34934788
Hm, I see that you commented out the foward declaration in Unit2.h - does it work if you remove the comment slashes?
0
 
LVL 2

Author Comment

by:alcindor
ID: 34934842
If I don't  comment out the forward declaration in unit 2 then I get a compiler error - Multiple declaration for Tc1
0
 
LVL 86

Expert Comment

by:jkr
ID: 34934986
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
 
LVL 2

Author Comment

by:alcindor
ID: 34935015
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
 
LVL 2

Author Comment

by:alcindor
ID: 34938419
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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

736 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question