Cannot compile simple example

M

Mtk

Hi!
Why does the following, simple, example produce such errors?
I know it has to do with the two header files including each other and
(moreover) the usage of the classes One and Two in the "opposite" header
file... What do I have to do to make this example work?

Thanks for all the help!

// * Error messages:
One.h(11): error C2146: syntax error : missing ';' before identifier 't'
One.h(11): error C2501: 'One::Two' : missing storage-class or type
specifiers
One.h(11): error C2501: 'One::t' : missing storage-class or type specifiers
Two.h(11): error C2146: syntax error : missing ';' before identifier 't'


// * File One.h
#ifndef ONE_H
#define ONE_H

#include "Two.h"

class One
{
public:
One();
private:
Two t;
};

#endif

// * File One.cpp
#include "One.h"

One::One()
{
}

// * File Two.h
#ifndef TWO_H
#define TWO_H

#include "One.h"

class Two
{
public:
Two();
private:
One t;
};

#endif

// * File Two.cpp
#include "Two.h"

Two::Two()
{
}

// * File Main.cpp
int main()
{
return 0;
}
 
R

Robert Macy

I'm new to this, too. So bear with me.

But your header files are CIRCULAR.

one defines the other. Walk through line by line and there is great
confusion.

You must straighten out the sequence of instructions so there is NO
ambiguity. Then it looks like it should compile ok.

- Robert -
 
?

=?iso-8859-1?Q?Ali_=C7ehreli?=

Why does the following, simple, example produce such errors?
I know it has to do with the two header files including each other

Because of the "include guards," the two files only look like including each
other. In effect, one of them includes the other one; and that's it. (Second
one includes the first one too, but at that time the body of the first
header is included as nothing.)
and (moreover) the usage of the classes One and Two in the "opposite"
header file... What do I have to do to make this example work?

You have to use a forward declaration and must use one of the classes as
reference (meaning both reference and pointer) in the other header.
// * Error messages:
One.h(11): error C2146: syntax error : missing ';' before identifier 't'
One.h(11): error C2501: 'One::Two' : missing storage-class or type
specifiers
One.h(11): error C2501: 'One::t' : missing storage-class or type
specifiers
Two.h(11): error C2146: syntax error : missing ';' before identifier 't'


// * File One.h
#ifndef ONE_H
#define ONE_H

#include "Two.h"

class One
{
public:
One();
private:
Two t;

That line is good; because we know what Two is.
};

#endif

// * File One.cpp
#include "One.h"

One::One()
{
}

// * File Two.h
#ifndef TWO_H
#define TWO_H

#include "One.h"

The line above is ineffective, because the macro ONE_H is defined at this
point, so what we include with the line above is "nothing."
class Two
{
public:
Two();
private:
One t;

You have a conceptual problem on the line above. It is not possible to have
two objects include each other; that would be infinite recursively.

At least one of your classes must "refer" to the other one; it should not
include it as a part.
};

#endif

Without knowing your exact requirements, here is one solution:

Don't include "One.h" in Two.h; instead, forward declare One. Then, keep a
reference to a One object in Two, don't contain one:

// * File Two.h
#ifndef TWO_H
#define TWO_H

class One; // <-- Forward declaration

class Two
{
public:
explicit Two(One & one) // <-- Take a reference
:
t(one) // <-- Remember your One
{}

private:
One & t; // <-- Keep a reference

};

#endif

By the way, I think this must be an FAQ.

Ali
 
V

Victor Bazarov

Mtk said:
Why does the following, simple, example produce such errors?
I know it has to do with the two header files including each other and
(moreover) the usage of the classes One and Two in the "opposite" header
file... What do I have to do to make this example work?

You can't.

Let's condense your example to one file. And let's suppose the compiler
knows about classes 'One' and 'Two' somehow _apriori_.
> [...]
class One
{
public:
One();
private:
Two t;
};
> [...]
class Two
{
public:
Two();
private:
One t;
};

Now, what is the size of a class One object? As soon as you can come up
with a formula the compiler can use to calculate it, let us know.

Meanwhile, look up "forward declaration".

V
 
M

Mtk

Thanks for the reply.

I may be a newbie when it comes to c++, but there must be a simpler
solution to my problem than the one you described.

Not including "One.h" in "Two.h", and attempting to forward-declare
class One, gives the error message "Two.h(10): error C2079: 'Two::t'
uses undefined class 'One'" - of course.

Anyway. I'll take a look at forward declarations.

Thanks again

Ali Çehreli wrote:
[huge snip]
 
?

=?iso-8859-1?Q?Ali_=C7ehreli?=

Mtk said:
Thanks for the reply.

I may be a newbie when it comes to c++, but there must be a simpler
solution to my problem than the one you described.

There isn't a simpler solution. We must break the circular dependency
somehow.
Not including "One.h" in "Two.h", and attempting to forward-declare class
One, gives the error message "Two.h(10): error C2079: 'Two::t' uses
undefined class 'One'" - of course.

Did you make Two::t a reference? (See my code below.)
Anyway. I'll take a look at forward declarations.

Here is an excellent read:

http://www.gotw.ca/gotw/007.htm

Check out the rest of the GotW archive as well :)

[...]

Ali
 
M

Mtk

Hi!

I forgot to mention that I'm a newbie and I have no intention to make
the compiler calculate the size of any class at all (at least for now)
and, thus, I'll skip that part.

I just want class One to have a variable of the "class Two"-type and
vice-versa, giving the requirement that each class is located in its own
header file.

I'll look "forward declarations" up.

Thanks

Victor said:
Mtk said:
Why does the following, simple, example produce such errors?
I know it has to do with the two header files including each other and
(moreover) the usage of the classes One and Two in the "opposite"
header file... What do I have to do to make this example work?

You can't.

Let's condense your example to one file. And let's suppose the compiler
knows about classes 'One' and 'Two' somehow _apriori_.
[...]
class One
{
public:
One();
private:
Two t;
};
[...]
class Two
{
public:
Two();
private:
One t;
};

Now, what is the size of a class One object? As soon as you can come up
with a formula the compiler can use to calculate it, let us know.

Meanwhile, look up "forward declaration".

V
 
A

Artie Gold

Mtk said:
Victor said:
Mtk said:
Why does the following, simple, example produce such errors?
I know it has to do with the two header files including each other
and (moreover) the usage of the classes One and Two in the "opposite"
header file... What do I have to do to make this example work?


You can't.

Let's condense your example to one file. And let's suppose the compiler
knows about classes 'One' and 'Two' somehow _apriori_.
class One
{
public:
One();
private:
Two t;
};

class Two
{
public:
Two();
private:
One t;
};


Now, what is the size of a class One object? As soon as you can come up
with a formula the compiler can use to calculate it, let us know.

Meanwhile, look up "forward declaration".

V

[top posting corrected]
> Hi!
>
> I forgot to mention that I'm a newbie and I have no intention to make
> the compiler calculate the size of any class at all (at least for now)
> and, thus, I'll skip that part.
>
That's not a good idea; understanding this is *absolutely central* to
your understanding of why you can't do what you're trying to do.
> I just want class One to have a variable of the "class Two"-type and
> vice-versa, giving the requirement that each class is located in its own
> header file.

Right. See above.
>
> I'll look "forward declarations" up.
>

HTH,
--ag
 
J

Jay Nabonne

I just want class One to have a variable of the "class Two"-type and
vice-versa, giving the requirement that each class is located in its own
header file.

But then a "One" object (which contains a "Two" object containing a "One"
object) would then, within itself, contain another complete One object.
Which contains a Two which contains a One which...

The only way this can make sense is if a One object is of infinite size.

- Jay
 
M

Mtk

Thanks!

I'm reading on ;)
Mtk said:
Thanks for the reply.

I may be a newbie when it comes to c++, but there must be a simpler
solution to my problem than the one you described.

There isn't a simpler solution. We must break the circular dependency
somehow.
Not including "One.h" in "Two.h", and attempting to forward-declare
class One, gives the error message "Two.h(10): error C2079: 'Two::t'
uses undefined class 'One'" - of course.

Did you make Two::t a reference? (See my code below.)
Anyway. I'll take a look at forward declarations.

Here is an excellent read:

http://www.gotw.ca/gotw/007.htm

Check out the rest of the GotW archive as well :)

[...]

Ali
 
A

Artie Gold

Mtk said:
But, top-posting IS the right thing to do ;)

Artie Gold wrote:
[snip]
[top posting corrected]

[snip]

In which case you've revealed yourself as a troll, thereby not worthy of
further attention. Of course, like all good trolls, you'll probably morph.

Great.

--ag
 
J

Jim Langston

Mtk said:
Hi!

I forgot to mention that I'm a newbie and I have no intention to make the
compiler calculate the size of any class at all (at least for now) and,
thus, I'll skip that part.

I just want class One to have a variable of the "class Two"-type and
vice-versa, giving the requirement that each class is located in its own
header file.

I'll look "forward declarations" up.

Thanks

Think about this a second. You want class One to include class two, and
class two to include class One. Lets look at it in a tree type way:

class One <-- class instance
class Two <-- includes class
class One <--- includes class
class Two <-- includes class
class One <-- includes class...

you see the problem? It goes on forever.

The solution? Keep a pointer or reference to the other class. A pointer or
reference is of a fixed size, no matter the size of the object it points to.
So now we have:

class One <-- class instance
class* Two <-- includes class pointer

and that's it. And class two now looks like:

class Two <-- class instance
class* One <-- includes class pointer

Now, you may be tempted to do something like this:

class Two;

class One
{
public:
One() { TwoPoint = new Two; }
private:
Two* TwoPoint;
};

class Two
{
public:
Two() { OnePoint = new One; }
private:
One* OnePoint;
};

But that won't work either, becuase now you've just moved the recursion from
compile time to run time. See, when you create your instance of class One
it calls the constructor for class two which creates and instance of class
One which calls the constructor for class two which...

You need to rethink your design and determine what it is you actually need.
 

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

Staff online

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top