allowing header files to call each other?

E

Eric

I am writing a program with several header files. I would like for some
of them to be aware of others. Here is a small example of my problem in
three different files:

//// main.c++
#include "A.h"
#include "B.h"

int main () {
using namespace std;
return 0;}

//// A.h
#ifndef A_h
#define A_h

class A{
public:
void call_b(B b){
b.dummy();}

void dummy(){
int i = 0;}}

#endif // A_h

////B.h
#ifndef B_h
#define B_h

class B{
public:
void call_a(A a){
a.dummy();}

void dummy(){
int i = 0;}}

#endif // B_h

<END>

This does not compile. Can anyone tell me why, and how to let A and B be
aware of each other?
 
M

Michael

I am writing a program with several header files. I would like for some
of them to be aware of others.
This does not compile. Can anyone tell me why, and how to let A and B be
aware of each other?

You need to do two things in this case: 1) forward declare your
classes, 2) separate class declaration from method definitions.

Here's the code. Explanation follows:

//// A.h
#ifndef A_h
#define A_h

class B; // Forward declaration

class A{
public:
void call_b(B b);
void dummy();
};

#endif // A_h

////B.h
#ifndef B_h
#define B_h

class A; // Forward declaration

class B{
public:
void call_a(A a);

void dummy();
};

#endif // B_h

//// A.cc
#include "A.h"
#include "B.h"

void A::call_b(B b){
b.dummy();
}


void A::dummy(){
int i = 0;
}

//// B.cc

#include "B.h"
#include "A.h"

void B::call_a(A a){
a.dummy();
}

void B::dummy(){
int i = 0;
}

//// main.cc
#include "A.h"
#include "B.h"


int main () {
return 0;
}

In the header files, you forward declare the classes (see comments in
code as to where this happens). So, in the header files, you know the
other class exists, but not any details about it. In the .cc files,
you need to use the other class, so you include both header files.
It's now kosher to do so, because the *declarations* in the header
files don't depend on each other, only the *definitions* (or
implementations) in the cc files do.

Michael
 
M

Mark P

Michael said:
You need to do two things in this case: 1) forward declare your
classes, 2) separate class declaration from method definitions.

Not good enough. To pass an object by value as a function argument
requires a complete definition of the class. A forward declaration
would only allow the argument to be a pointer or reference to the
forward declared class type.
 
E

Eric

Mark said:
Not good enough. To pass an object by value as a function argument
requires a complete definition of the class. A forward declaration
would only allow the argument to be a pointer or reference to the
forward declared class type.

What about by reference?
 
M

Michael

Mark said:
Not good enough. To pass an object by value as a function argument
requires a complete definition of the class. A forward declaration
would only allow the argument to be a pointer or reference to the
forward declared class type.

I don't have my copy of the standard handy, but my impression was that
you need the full definition at the point you *call* such a function,
but not necessarily at the point you *declare* such a function. Since
you have the full definition in the .cc files, you should be set.

Not that it matters, but this code compiles and runs on my compiler.
:)

Michael
 
I

Ian Collins

Michael said:
I don't have my copy of the standard handy, but my impression was that
you need the full definition at the point you *call* such a function,
but not necessarily at the point you *declare* such a function. Since
you have the full definition in the .cc files, you should be set.
No, Mark is correct. You have to know the object's size, which requires
the declaration.

Make sure you don't confuse the terms declaration and definition.
 
M

Michael

#ifndef A_h
No, Mark is correct. You have to know the object's size, which requires
the declaration.

I hate to belabor this, but you guys are wrong on this point. The
original code I posted is correct and conforms to the standard.

I would point you to Herb Sutter's Guru of the Week column:
http://www.gotw.ca/gotw/007.htm

It includes an example of exactly this type:
//---------------------------------------------------------------
// new file y.h: ZERO includes!
//
class A;
class C;

class Y {
public:
C Function4( A );
private:
class YImpl* pimpl_;
};

And in the text of the article (point 4):
... y.h does not need to include a.h since it only uses A as a
function
parameter type, which does not require a definition.

Naturally, you need to include A.h where you want to create the objects
of type A to pass into the method, but in my original example I did
exactly that - A.h was included in the .cc files that used it.

The point is that you *don't* need the full declaration of A to use A
as a function parameter *in a declaration*; the forward declaration is
enough. You *do* need the full declaration of A to use A - either to
instantiate it, to access its members, or to call the methods that take
A as a function parameter. But all of those cases, in the example code
I posted to answer the OP, occur in .cc files, where A.h *is* included.

Of course, maybe you want to switch to references or pointers or
whatever. And you're welcome to. But you don't have to. This point
might be important if, for example, you had a bunch of legacy code -
you can simplify the header file dependencies without having to change
function signatures and rewrite other code and potentially introduce
bugs.

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top