cyclic defination problem.

Discussion in 'C++' started by toton, Aug 14, 2006.

  1. toton

    toton Guest

    Hi I have a class called Session, which stores a vector of Page, like
    vector<Page> Also each Page need's to know the Session to which it is
    attached.

    Thus I have, (the classes has many other things, I copied only the
    portion i needed)
    in Session.hpp

    #include "Page.hpp"
    class Session {
    private:
    std::vector<Page> _pages;
    };

    while in Page.hpp
    class Session;// forward decl
    class Page{
    private:
    Session* _session;
    public:
    Page(Session* session) : _session(session) {}
    };
    Is it the best way to remove cyclic definition problem? Or any way I
    can store a reference to Session rather than pointer to Session?

    Thanks
    abir
     
    toton, Aug 14, 2006
    #1
    1. Advertising

  2. toton wrote:
    > Hi I have a class called Session, which stores a vector of Page, like
    > vector<Page> Also each Page need's to know the Session to which it is
    > attached.
    >
    > Thus I have, (the classes has many other things, I copied only the
    > portion i needed)
    > in Session.hpp
    >
    > #include "Page.hpp"
    > class Session {
    > private:
    > std::vector<Page> _pages;
    > };
    >
    > while in Page.hpp
    > class Session;// forward decl
    > class Page{
    > private:
    > Session* _session;
    > public:
    > Page(Session* session) : _session(session) {}
    > };
    > Is it the best way to remove cyclic definition problem? Or any way I
    > can store a reference to Session rather than pointer to Session?


    Whether to store a reference to Session or a pointer to Session is up
    to you, and either would require using some kind of forward declaration,
    which you have done already. Keep in mind that if you store a reference
    in 'Page' you will have to initialise it during construction of the Page
    object and you will not be able to change it during the Page's lifetime.
    If that fits your design, prefer the reference. Otherwise, go with the
    pointer.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 14, 2006
    #2
    1. Advertising

  3. toton

    mlimber Guest

    toton wrote:
    > Hi I have a class called Session, which stores a vector of Page, like
    > vector<Page> Also each Page need's to know the Session to which it is
    > attached.
    >
    > Thus I have, (the classes has many other things, I copied only the
    > portion i needed)
    > in Session.hpp
    >
    > #include "Page.hpp"
    > class Session {
    > private:
    > std::vector<Page> _pages;
    > };
    >
    > while in Page.hpp
    > class Session;// forward decl
    > class Page{
    > private:
    > Session* _session;
    > public:
    > Page(Session* session) : _session(session) {}
    > };
    > Is it the best way to remove cyclic definition problem? Or any way I
    > can store a reference to Session rather than pointer to Session?


    You could have a reference (it's simple enough to test -- did you try
    it?). See this article for more on forward declarations and breaking
    dependencies:

    http://www.gotw.ca/publications/mill04.htm

    Cheers! --M
     
    mlimber, Aug 14, 2006
    #3
  4. toton

    John Carson Guest

    "mlimber" <> wrote in message
    news:
    > toton wrote:
    >> Hi I have a class called Session, which stores a vector of Page, like
    >> vector<Page> Also each Page need's to know the Session to which it is
    >> attached.
    >>
    >> Thus I have, (the classes has many other things, I copied only the
    >> portion i needed)
    >> in Session.hpp
    >>
    >> #include "Page.hpp"
    >> class Session {
    >> private:
    >> std::vector<Page> _pages;
    >> };
    >>
    >> while in Page.hpp
    >> class Session;// forward decl
    >> class Page{
    >> private:
    >> Session* _session;
    >> public:
    >> Page(Session* session) : _session(session) {}
    >> };
    >> Is it the best way to remove cyclic definition problem? Or any way I
    >> can store a reference to Session rather than pointer to Session?

    >
    > You could have a reference (it's simple enough to test -- did you try
    > it?).


    Use of a reference is a little tricky.

    Page is stored in a vector and objects stored in standard containers must be
    assignable. The compiler won't generate an assignment operator for Page,
    because a reference cannot be re-seated.

    You could write an assignment operator for Page to get the code to compile,
    but any user-defined assignment operator likewise will not re-seat a
    reference, so there could be some unexpected behaviour.

    --
    John Carson
     
    John Carson, Aug 14, 2006
    #4
  5. toton

    mlimber Guest

    John Carson wrote:
    > "mlimber" <> wrote in message
    > news:
    > > toton wrote:
    > >> Hi I have a class called Session, which stores a vector of Page, like
    > >> vector<Page> Also each Page need's to know the Session to which it is
    > >> attached.
    > >>
    > >> Thus I have, (the classes has many other things, I copied only the
    > >> portion i needed)
    > >> in Session.hpp
    > >>
    > >> #include "Page.hpp"
    > >> class Session {
    > >> private:
    > >> std::vector<Page> _pages;
    > >> };
    > >>
    > >> while in Page.hpp
    > >> class Session;// forward decl
    > >> class Page{
    > >> private:
    > >> Session* _session;
    > >> public:
    > >> Page(Session* session) : _session(session) {}
    > >> };
    > >> Is it the best way to remove cyclic definition problem? Or any way I
    > >> can store a reference to Session rather than pointer to Session?

    > >
    > > You could have a reference (it's simple enough to test -- did you try
    > > it?).

    >
    > Use of a reference is a little tricky.
    >
    > Page is stored in a vector and objects stored in standard containers must be
    > assignable. The compiler won't generate an assignment operator for Page,
    > because a reference cannot be re-seated.
    >
    > You could write an assignment operator for Page to get the code to compile,
    > but any user-defined assignment operator likewise will not re-seat a
    > reference, so there could be some unexpected behaviour.


    Right, and the same is true if one used a const pointer to a Session
    object instead (const-correctness and all that). I took the OP's
    question to be about whether a forward declaration would work with a
    reference as well as a pointer, which, of course, it will.

    Cheers! --M
     
    mlimber, Aug 14, 2006
    #5
  6. toton

    toton Guest

    Victor Bazarov wrote:
    > toton wrote:
    > > Hi I have a class called Session, which stores a vector of Page, like
    > > vector<Page> Also each Page need's to know the Session to which it is
    > > attached.
    > >
    > > Thus I have, (the classes has many other things, I copied only the
    > > portion i needed)
    > > in Session.hpp
    > >
    > > #include "Page.hpp"
    > > class Session {
    > > private:
    > > std::vector<Page> _pages;
    > > };
    > >
    > > while in Page.hpp
    > > class Session;// forward decl
    > > class Page{
    > > private:
    > > Session* _session;
    > > public:
    > > Page(Session* session) : _session(session) {}
    > > };
    > > Is it the best way to remove cyclic definition problem? Or any way I
    > > can store a reference to Session rather than pointer to Session?

    >
    > Whether to store a reference to Session or a pointer to Session is up
    > to you, and either would require using some kind of forward declaration,
    > which you have done already. Keep in mind that if you store a reference
    > in 'Page' you will have to initialise it during construction of the Page
    > object and you will not be able to change it during the Page's lifetime.
    > If that fits your design, prefer the reference. Otherwise, go with the
    > pointer.

    I prefer to store reference. Infact I want to do it in ctor, as you
    have mentioned. I prefer not to change it. I also prefer to have a
    constant reference.
    like
    class Page{
    private:
    const Session& _session;
    };
    but, at the same time, I prefer to pass it in the constructor as
    reference, rather than pointer.
    like Page(const Session& session) : _session(session) {}
    Here some cyclic definition creating problem. I am not sure whether
    this can be done, i.e only forward defination will allow me to do so or
    not, or in my case problem is coming from some other cyclic
    definition.
    Thanks...
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask
     
    toton, Aug 14, 2006
    #6
  7. toton wrote:
    > [..]
    > I prefer to store reference. Infact I want to do it in ctor, as you
    > have mentioned. I prefer not to change it. I also prefer to have a
    > constant reference.
    > like
    > class Page{
    > private:
    > const Session& _session;
    > };
    > but, at the same time, I prefer to pass it in the constructor as
    > reference, rather than pointer.
    > like Page(const Session& session) : _session(session) {}
    > Here some cyclic definition creating problem. I am not sure whether
    > this can be done, i.e only forward defination will allow me to do so
    > or not, or in my case problem is coming from some other cyclic
    > definition.


    Pull the _implementation_ of the constructor out of your 'Page' class
    definition. Place it along with other Page's member functions in its
    own implementation file (translation unit), and include both headers
    in it (in any order) before defining all functions.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 14, 2006
    #7
  8. toton

    toton Guest

    Victor Bazarov wrote:
    > toton wrote:
    > > [..]
    > > I prefer to store reference. Infact I want to do it in ctor, as you
    > > have mentioned. I prefer not to change it. I also prefer to have a
    > > constant reference.
    > > like
    > > class Page{
    > > private:
    > > const Session& _session;
    > > };
    > > but, at the same time, I prefer to pass it in the constructor as
    > > reference, rather than pointer.
    > > like Page(const Session& session) : _session(session) {}
    > > Here some cyclic definition creating problem. I am not sure whether
    > > this can be done, i.e only forward defination will allow me to do so
    > > or not, or in my case problem is coming from some other cyclic
    > > definition.

    >
    > Pull the _implementation_ of the constructor out of your 'Page' class
    > definition. Place it along with other Page's member functions in its
    > own implementation file (translation unit), and include both headers
    > in it (in any order) before defining all functions.


    Now cyclic definition problem is solved, but one more problem arises.
    When I declare Session as pointer inside Page, and use a vector<Page>
    inside session, it works fine.

    However, when I declare Session as reference inside Page and use
    vector<Page> in session, vector<Page> unable to find the assignment
    operator for Page.
    I hadn't defined the assignment operator for Page explicitly, ( I only
    have a ctor, & virtual dtor, not defined copy ctor, assignment operator
    or equality operator explicitly). It seems, that for the reference
    case, Page class is not defining assignment operator automatically,
    however it defines when I am passing pointer to Session in Page. and
    thus vector<Page> is having problem inside Session class.
    Do I need to define assignment operator explicitly in this case?
    thanks
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask
     
    toton, Aug 16, 2006
    #8
  9. toton wrote:
    > [..]
    > Now cyclic definition problem is solved, but one more problem arises.
    > When I declare Session as pointer inside Page, and use a vector<Page>
    > inside session, it works fine.
    >
    > However, when I declare Session as reference inside Page and use
    > vector<Page> in session, vector<Page> unable to find the assignment
    > operator for Page.
    > I hadn't defined the assignment operator for Page explicitly, ( I only
    > have a ctor, & virtual dtor, not defined copy ctor, assignment
    > operator or equality operator explicitly). It seems, that for the
    > reference case, Page class is not defining assignment operator
    > automatically, however it defines when I am passing pointer to
    > Session in Page. and thus vector<Page> is having problem inside
    > Session class.
    > Do I need to define assignment operator explicitly in this case?
    > thanks


    Yes, assignment operators are very tricky when your class has a member
    that is a reference. References cannot be "reseated", i.e. made to
    refer to another object than the one with which they were initialised.
    So, imagine you have

    class A {};
    class B {
    A & a;
    public:
    B(A& ra) : a(ra) {}
    };

    The compiler does not know how to generate the assignment operator
    for class 'B', since the assignment semantics for references are to
    assign the objects and since you're keeping the reference in 'B', you
    clearly don't want to affect the objects you refer to. You can write
    your own assignment operator and forgo doing anything special about
    the reference member (like this:

    B& operator =(const B& other_b) {
    // do nothing
    return *this;
    }

    ) which means that when assigned new value, a B object will retain
    the reference, IOW its 'a' member will still refer to what the object
    was constructed to refer to. Is that what you want? I don't know.
    If you want "reseat-ability", use pointers.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 16, 2006
    #9
  10. toton

    toton Guest

    Victor Bazarov wrote:
    > toton wrote:
    > > [..]
    > > Now cyclic definition problem is solved, but one more problem arises.
    > > When I declare Session as pointer inside Page, and use a vector<Page>
    > > inside session, it works fine.
    > >
    > > However, when I declare Session as reference inside Page and use
    > > vector<Page> in session, vector<Page> unable to find the assignment
    > > operator for Page.
    > > I hadn't defined the assignment operator for Page explicitly, ( I only
    > > have a ctor, & virtual dtor, not defined copy ctor, assignment
    > > operator or equality operator explicitly). It seems, that for the
    > > reference case, Page class is not defining assignment operator
    > > automatically, however it defines when I am passing pointer to
    > > Session in Page. and thus vector<Page> is having problem inside
    > > Session class.
    > > Do I need to define assignment operator explicitly in this case?
    > > thanks

    >
    > Yes, assignment operators are very tricky when your class has a member
    > that is a reference. References cannot be "reseated", i.e. made to
    > refer to another object than the one with which they were initialised.
    > So, imagine you have
    >
    > class A {};
    > class B {
    > A & a;
    > public:
    > B(A& ra) : a(ra) {}
    > };
    >
    > The compiler does not know how to generate the assignment operator
    > for class 'B', since the assignment semantics for references are to
    > assign the objects and since you're keeping the reference in 'B', you
    > clearly don't want to affect the objects you refer to. You can write
    > your own assignment operator and forgo doing anything special about
    > the reference member (like this:
    >
    > B& operator =(const B& other_b) {
    > // do nothing
    > return *this;
    > }
    >
    > ) which means that when assigned new value, a B object will retain
    > the reference, IOW its 'a' member will still refer to what the object
    > was constructed to refer to. Is that what you want? I don't know.
    > If you want "reseat-ability", use pointers.


    In my situation, the reference of Session (or pointer, still not
    decided! ) to a Page, and Page can not change the Session, it can only
    refer to the Session it belongs. Thus Page knows the Session it belongs
    at construction (in ctor) , and do not have a method like setSession.
    So, I don't think it is "reseat-able", a Page is associated with a
    Session throughout it's lifetime, and Session can remove a Page from
    its evctor<Page> if the processing is done. Similarly, a Char knows The
    Page it belongs, and can refer it, but itself can't change the Page it
    belongs. However a Page can remove the a Char from it's deque<Char>.
    That is why I thught reference is a better option.
    If I define the assignment operator as you have mentioned, does it mean
    that for two page
    Page p1,p2; if I write p1 = p2, then p1 will not get modified
    irrespective of what p2 is or will it be same object as p2 ?
    Also, will the copy constructor work in its usual way? As I have a
    vector<Page> inside the session, copy contsructor for Page is needed
    for Session to work properly.
    thanks.
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask
     
    toton, Aug 16, 2006
    #10
  11. toton wrote:
    > [..]
    > If I define the assignment operator as you have mentioned, does it
    > mean that for two page
    > Page p1,p2; if I write p1 = p2, then p1 will not get modified
    > irrespective of what p2 is or will it be same object as p2 ?


    Modify anything you want, just don't touch the reference (in any way).
    The assignment operator should perform all actions necessary to copy
    data members. It's not possible to copy references (only copy objects
    to which they refer), so usually you'd leave references alone. Thus,
    the reference refers to the same object throughout its lifetime, no
    matter whether the other members get changed along the way using the
    assignment operator.

    > Also, will the copy constructor work in its usual way?


    That should be fine.

    > As I have a
    > vector<Page> inside the session, copy contsructor for Page is needed
    > for Session to work properly.


    Sure. Will not be a problem.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Aug 16, 2006
    #11
    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. cvsta
    Replies:
    0
    Views:
    2,293
    cvsta
    Jul 12, 2004
  2. Guo Congbin
    Replies:
    4
    Views:
    3,929
    Ioannis Vranos
    Jun 17, 2004
  3. scl

    two defination ?

    scl, Mar 19, 2005, in forum: C++
    Replies:
    8
    Views:
    2,800
    modemer
    Mar 21, 2005
  4. sunnylele

    A question on variable defination

    sunnylele, Mar 31, 2006, in forum: C Programming
    Replies:
    3
    Views:
    335
    Eric Sosman
    Mar 31, 2006
  5. venky

    Is it declaration or defination?

    venky, Aug 18, 2006, in forum: C Programming
    Replies:
    25
    Views:
    774
    =?UTF-8?B?Ik5pbHMgTy4gU2Vsw6VzZGFsIg==?=
    Aug 21, 2006
Loading...

Share This Page