Thread: Object of class A that has a member of object of class B and vice versa

  1. #1
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476

    Object of class A that has a member of object of class B and vice versa

    Hi guys, like the title says, how do you handle two classes (and one of them is a singleton) that references one another? I've got these currently:

    singleton_A.h:
    Code:
    #include "class_A.h"
    
    class ClassA; // Forward Declaration
    
    class SingletonA
    {
        ...... //The usual singleton routines
        ClassA* mA;
    }
    class_A.h:
    Code:
    #include "class_B.h"
    #include "singleton_A.h"
    
    class ClassA : public ClassB
    {
      ....
    }
    FYI, there's a lot of SingletonA::getInstance()... inside of both ClassA and ClassB.

    The problem with this is the ClassB cannot be compiled because apparently ClassB, while being the parent of ClassA, also calls the singleton (which in turn has ClassA as its member). I know that this is probably just an issue of bad design. But then again how do I solve this?

    The requirements are:
    1. ClassA and ClassB both calls a function from SingletonA
    2. SingletonA needs some data from ClassA that are required to process the output for the functions that are called by ClassA and ClassB.

    Can anybody help me please? I'm so lost right now. Thanks in advance.
    ERROR: Brain not found. Please insert a new brain!

    “Do nothing which is of no use.” - Miyamoto Musashi.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by g4j31a5
    The problem with this is the ClassB cannot be compiled because apparently ClassB, while being the parent of ClassA, also calls the singleton (which in turn has ClassA as its member). I know that this is probably just an issue of bad design. But then again how do I solve this?
    I do not see the problem. singleton_A.h only has a forward declaration of ClassA, so you can include it in class_B.h.

    Just to check: you are using header inclusion guards, right?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by laserlight View Post
    I do not see the problem. singleton_A.h only has a forward declaration of ClassA, so you can include it in class_B.h.

    Just to check: you are using header inclusion guards, right?
    That's what I thought. Apparently the compiler didn't agree with me. It said this:
    13>class_B.cc
    13>../engine\frogger/class_A.h(17) : error C2504: 'class_B' : base class undefined
    So I guess when the compiler tries to compile class_B, it recognized the "Windowing::getInstance()" token and in turn tries to compile class_A but because because class_A is the child of class_B, it goes recursively. CMIIW.

    Also, yeah, I always use the inclusion guards.

    Ok, I think my class design itself is not correct. Any idea on how to go around this?

    What I want to do is to solve this:
    1. ClassA and ClassB both calls functions from SingletonA.
    2. SingletonA needs some data from ClassA that are required to process the output for the functions that are called by ClassA and ClassB.
    ERROR: Brain not found. Please insert a new brain!

    “Do nothing which is of no use.” - Miyamoto Musashi.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Wait a minute. I missed this on the first line of singleton_A.h:
    Code:
    #include "class_A.h"
    Remove that line. You are using a forward declaration, remember?

    If that does not solve the problem, post the smallest and simplest program that demonstrates the problem. In addition to all three headers, post the relevant source files, just in case.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Ok, I think my class design itself is not correct. Any idea on how to go around this?

    What I want to do is to solve this:
    Quote:
    1. ClassA and ClassB both calls functions from SingletonA.
    2. SingletonA needs some data from ClassA that are required to process the output for the functions that are called by ClassA and ClassB.
    Hard to say without concrete examples. What do ClassA, ClassB, and SingletonA do?

  6. #6
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    @laserlight:
    Nope, didn't work. It said this:
    13>..\engine\frogger\singletonA.cc(200) : error C2027: use of undefined type 'class_A'
    13> ../engine\frogger/singletonA.h(104) : see declaration of 'class_A'
    But I think I've got it fixed now. Thanks to your suggestion, instead of removing that include line, I moved it to the source file. It can be compiled now. So, now what's left is to check whether or not they do the job right.

    @medievalelks:
    Well, actually they are not named class_A, class_B, and singletonA (obviously). It was Player (class_A / child), Object (class_B / parent), and GameManager (singletonA). GameManager has this function:
    Code:
    bool GameManager ::getState(const int lane) const
    {
    	return mLaneState[lane] && (mPlayer->getCurrentLane() == lane);
    }
    And both Player / class_A and Object / class_B need to call this method but in different places. This is used in this scenario: "if the object is in the same lane as the player and the lane was tagged as true (meaning it was a chasing-zone), it would chase the player. and also the player in turn will be notified that there is / are an object(s) chasing it."

    I know perhaps there's a pattern in GoF's book for this but alas the only pattern I'm familiar with are Singleton and Facade. :P
    ERROR: Brain not found. Please insert a new brain!

    “Do nothing which is of no use.” - Miyamoto Musashi.

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    You use forward references in headers (thus removing circular dependencies between them) and include the headers in sources.

    BTW, singleton is hardly a pattern to use a lot. Most of the time ensuring that there be only one is irrelevant (or a hindrance if it turns out having more than one instance would be useful), and only the global aspect remains (with all the evils of global variables).
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    @medievalelks:
    Well, actually they are not named class_A, class_B, and singletonA (obviously). It was Player (class_A / child), Object (class_B / parent), and GameManager (singletonA). GameManager has this function:
    Perhaps GameManager is a bloated interface with too much responsibility. Can you factor out the functions needed by the Objects (including Player) that it manages into a different class or classes?

  9. #9
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    @anon:

    Yeah, that may be the case. I have never used forward declaration before. I always try to do it another way if possible because I always see it as a bad practice.

    Yeah, singleton is not that good of a pattern. But it served its purpose for me.

    @medievalelks:

    I'm not sure I understand your question. Can you elaborate more?

    BTW, a little OOT, but still has some connection with my original question, question. How do you solve a condition where one class has a reference to another class and vice versa, and also each class has to be aware of any changes of the other? E.g.:

    Code:
    class ClassA
    {
    
         ClassB* mB;
    };
    
    
    class ClassB
    {
    
         ClassA* mA;
    };
    Forward declaration only or are there any other option?
    ERROR: Brain not found. Please insert a new brain!

    “Do nothing which is of no use.” - Miyamoto Musashi.

  10. #10
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    What I meant was, it appears that Objects -- which are held by GameManager -- have to reach back into GameManager for functionality. Can you move that functionality to another class so that they don't have to reach back?

  11. #11
    In the Land of Diddly-Doo g4j31a5's Avatar
    Join Date
    Jul 2006
    Posts
    476
    Quote Originally Posted by medievalelks View Post
    What I meant was, it appears that Objects -- which are held by GameManager -- have to reach back into GameManager for functionality. Can you move that functionality to another class so that they don't have to reach back?
    Sorry for the long delay. The one that is held by GameManager is Player, which is the child of Object, not the Object itself. FYI, this is my first attempt to remake the GameManager singleton. Before this, I just copied all the needed variables from Player (which are almost all the member variables of the class Player) to GameManager. Some of them are: the player's current lane position, orientation, velocity, etc. So everytime those variables need to change their value, they do it twice. Once in the Player class and once in the GameManager. And because I thought it seems redundant, I decided to just rewrite the whole class and pass the Player as the member variable of GameManager. I use "GameManager::getInstance()->setPlayer(this)" in Player's constructor so everytime the Player is created, it would automatically be set into the GameManager.

    I don't know if I can move those functionalities to another class because the Player is one of the essential member variables from GameManager. It needed to know the status of the Player constantly.

    Anyway, I think it's safe to say that it's a wrap for now. Thanks guys.
    ERROR: Brain not found. Please insert a new brain!

    “Do nothing which is of no use.” - Miyamoto Musashi.

Popular pages Recent additions subscribe to a feed