Cannot compile simple example

Discussion in 'C++' started by Mtk, Oct 10, 2005.

  1. Mtk

    Mtk Guest

    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;
    }
    Mtk, Oct 10, 2005
    #1
    1. Advertising

  2. Mtk

    Robert Macy Guest

    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 -
    Robert Macy, Oct 10, 2005
    #2
    1. Advertising

  3. "Mtk" <> wrote in message
    news:die8qp$1f3$...

    > 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
    =?iso-8859-1?Q?Ali_=C7ehreli?=, Oct 10, 2005
    #3
  4. Mtk wrote:
    > 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
    Victor Bazarov, Oct 10, 2005
    #4
  5. Mtk

    Mtk Guest

    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]
    > 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
    >
    Mtk, Oct 10, 2005
    #5
  6. "Mtk" <> wrote in message
    news:diedbq$2h4$...
    > 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 :)

    [...]

    >> // * 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
    >>
    >> };


    Ali
    =?iso-8859-1?Q?Ali_=C7ehreli?=, Oct 10, 2005
    #6
  7. Mtk

    Mtk Guest

    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 Bazarov wrote:
    > Mtk wrote:
    >> 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
    Mtk, Oct 10, 2005
    #7
  8. Mtk

    Artie Gold Guest

    Mtk wrote:
    >
    > Victor Bazarov wrote:
    >
    >> Mtk wrote:
    >>
    >>> 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

    --
    Artie Gold -- Austin, Texas
    http://goldsays.blogspot.com (new post 8/5)
    http://www.cafepress.com/goldsays
    "If you have nothing to hide, you're not trying!"
    Artie Gold, Oct 10, 2005
    #8
  9. Mtk

    Jay Nabonne Guest

    On Mon, 10 Oct 2005 21:08:18 +0200, Mtk wrote:


    >
    > 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
    Jay Nabonne, Oct 10, 2005
    #9
  10. Mtk

    Mtk Guest

    Thanks!

    I'm reading on ;)

    Ali Çehreli wrote:
    > "Mtk" <> wrote in message
    > news:diedbq$2h4$...
    >> 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 :)
    >
    > [...]
    >
    >>> // * 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
    >>>
    >>> };

    >
    > Ali
    >
    Mtk, Oct 10, 2005
    #10
  11. Mtk

    Mtk Guest

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

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

    [snip]
    Mtk, Oct 10, 2005
    #11
  12. Mtk

    Artie Gold Guest

    Mtk wrote:
    > 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

    --
    Artie Gold -- Austin, Texas
    http://goldsays.blogspot.com (new post 8/5)
    http://www.cafepress.com/goldsays
    "If you have nothing to hide, you're not trying!"
    Artie Gold, Oct 10, 2005
    #12
  13. Thomas J. Gritzan, Oct 11, 2005
    #13
  14. Mtk

    Jim Langston Guest

    "Mtk" <> wrote in message
    news:diee2u$2l8$...
    > 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.
    Jim Langston, Oct 11, 2005
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?ISO-8859-1?Q?Martin_J=F8rgensen?=

    cannot compile the following example code (person-pointer)

    =?ISO-8859-1?Q?Martin_J=F8rgensen?=, Mar 25, 2006, in forum: C++
    Replies:
    26
    Views:
    643
    Alex Buell
    Mar 31, 2006
  2. Nagaraj
    Replies:
    1
    Views:
    832
    Lionel B
    Mar 1, 2007
  3. Saqib Ali
    Replies:
    7
    Views:
    982
    Saqib Ali
    Oct 18, 2011
  4. Sam Roberts
    Replies:
    15
    Views:
    273
    Sam Roberts
    Feb 7, 2005
  5. nudnik
    Replies:
    2
    Views:
    407
    Juha Nieminen
    Sep 28, 2012
Loading...

Share This Page