Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » cyclic dependencies

This thread is locked; no one can reply to it. rss feed Print
cyclic dependencies
Frank Drebin
Member #2,987
December 2002
avatar

how can i solve this problem:

//file1.cpp

class a
{
public:
void do_something_with_b();
};

void a::do_something_with_b()
{
b.do_something();
}

//file2.cpp

class b
{
public:
void do_something_with_a();
};

void b::do_something_with_a()
{
a.do_something();
}

Thomas Fjellstrom
Member #476
June 2000
avatar

put the class declaration in thier own .h file, and include then where needed.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

mEmO
Member #1,124
March 2001
avatar

Are you sure you're not confusing class declarations and objects? A class is a template for an object, not the object itself. To use it properly, do like this:

class Foo
{
 public:

 int var;
};

Foo bar;
bar.var = 2;

Just to make sure, though.

---------------------------------------------
There is only one God, and Connor is his son!
http://www.memocomputers.com
Happy birthday!

Torbjörn Josefsson
Member #1,048
September 2000
avatar

There's No way to protect against this kind of 'logical bug'

Simply don't write the program in this way.

It's the same thing as writing:

void do_something(){
   do_something();
}

It's a recursive situation without any exit condition.

If you want to make sure each one is only called once (I'm not sure what you're trying to do), you have to perform a check to see that it doesn't continue forever - maybe pass along an integer counter in the call, increment it for each call, and see if it exceeds some max value for recursive calls?

--
Specialization is for insects

Frank Drebin
Member #2,987
December 2002
avatar

perhaps the example i gave is not very well
but i found a solution for this:
just put all header files of the classes in one big header file and include this file in every sourcefile so that each class knows the others

Thomas Harte
Member #33
April 2000
avatar

So, you're problem was not one of functions calling each other, but one where the first class didn't know the definition of the other? Don't forget that you can use forward defintions, like :

class Elephant;

class Mouse
{
   ...
   Elephant *ScaredCreature;
   ...
};

class Elephant
{
   ...
   Mouse *ScaryCreature;
   ...
};

i.e. if the compiler really only needs to know that Elephant exists as a class (rather than being fussed about members), then that is all you need to tell it.

You know how I found that out? I had a little hunchback at the office.

Frank Drebin
Member #2,987
December 2002
avatar

yes with a pointer to a class this may work but when you declare a variable of that class it doesn't
like this:

class Elephant;

class Mouse
{
...
Elephant ScaredCreature;
...
};

class Elephant
{
...
Mouse ScaryCreature;
...
};

X-G
Member #856
December 2000
avatar

Frank Drebin said:

yes with a pointer to a class this may work but when you declare a variable of that class it doesn't

There's a good reason for that. For one thing, each of the resulting classes would be infinitely large, as they contain each other. ::)

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Frank Drebin
Member #2,987
December 2002
avatar

so how can i break a dependencie like that:
the class player needs to know the class bullet (and its firing method) and the bullet needs to know about the player (for collision detection)

X-G
Member #856
December 2000
avatar

Obviously, your only chance is to use pointers.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

gillius
Member #119
April 2000

If you need A to know about B and B to know about A you CANNOT have A contain B and B contain A. That makes no sense and it would go on forever.

You must use pointers or references and you must use forward delcarations as was shown to you earlier. Do not place all classes in one big header or whatever you were considering. In your class header, instead of doing #include "Class.h", replace it with class Class; as much as possible. As long as the class you are defining does not inherit from Class, does not contain a Class object, and does not have any methods taking a copy of a Class object (ie only Class* and Class& are seen), you can and should use forward declarations.

Gillius
Gillius's Programming -- https://gillius.org/

miran
Member #2,407
June 2002

And of course you should use include guards (or whatever they're called):

1//file Enemy.h
2#ifndef ENEMY_H
3#define ENEMY_H
4 
5class Bullet;
6class Enemy {
7 protected:
8 list <Bullet *> bullets;
9 
10 public:
11 // whatever
12};
13 
14#endif //ENEMY_H
15 
16 
17 
18//file Bullet.h
19#ifndef BULLET_H
20#define BULLET_H
21 
22class Enemy;
23class Bullet {
24 protected:
25 Enemy *parent;
26 
27 public:
28 // whatever
29};
30 
31#endif //BULLET_H

--
sig used to be here

Frank Drebin
Member #2,987
December 2002
avatar

o.k. but i'm not very good in pointers, so when i just declare a pointer to the bullet class in the player class how can i call then the bullet.fireit() method ???

23yrold3yrold
Member #1,134
March 2001
avatar

Quote:

o.k. but i'm not very good in pointers, so when i just declare a pointer to the bullet class in the player class how can i call then the bullet.fireit() method

Well, first you need to create a bullet (using new), but I'm sure you knew that. Then you can call
bullet->fireit().

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Frank Drebin
Member #2,987
December 2002
avatar

1. so i can use
"pointer_to_bullet=new bullet;" and
"pointer_to_bullet->fireit();"
in the player.cpp code without having declared
the class bullet before
(just forward declaration like "class
bullet;") ???

2. and when theres a global object bullet1
i can use
"pointer_to_bullet=&bullet1;" and
"pointer_to_bullet->fireit();"
... ???

23yrold3yrold
Member #1,134
March 2001
avatar

1. No. You need to have declared the class, not just a forward declaration (I call these class prototypes as they are like function prototypes. I may be the only person that does that, though ;)). If you don't declare the class, how is it going to know that it has a member function called fireit()?

You can organize it like this, just as an example:

1class Bullet
2{
3 void fireit();
4};
5 
6Bullet* somefunction()
7{
8 Bullet* b = new Bullet;
9 b->fireit();
10 return b;
11}
12 
13void Bullet::fireit()
14{
15 // whatever
16}

You can define fireit() (and all of Bullet's other functions) in a seperate file if you want. But if you want to access Bullet's members, you must declare the members first.

2. Sounds right ....

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

X-G
Member #856
December 2000
avatar

Creepy Disembodied Bearded Tycho Head said:

I call these class prototypes

You should call them classes, simple enough. ;)
Once you instantiate it, it's an object. Class is to object what prototype is to function, one could say. I think. ;)

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

23yrold3yrold
Member #1,134
March 2001
avatar

Nonono ...

   // class prototype
   class Bullet;

   // class declaration
   class Bullet
   {
      public:
         Bullet();
         ~Bullet();
         void fireit();
   };

   // class definition
   Bullet::Bullet(){
      // blah blah blah
   }

   Bullet::~Bullet(){
      // blah blah blah
   }
   void Bullet::fireit(){
      // blah blah blah
   }

Geddit?

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

X-G
Member #856
December 2000
avatar

How interesting, then, that there are no such in the code snippet. ;)

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

23yrold3yrold
Member #1,134
March 2001
avatar

Huh? Look at Frank's last post. I know I didn't use one; it wouldn't have worked. That was the point ;)

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

X-G
Member #856
December 2000
avatar

Just call them forward declarations like everyone else, all right? ;)

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

23yrold3yrold
Member #1,134
March 2001
avatar

I called one thing a class prototype, and another thing a class declaration. Which one is the forward declaration, can we call function prototypes that, and what do you call the other class thing (whichever isn't a declaration)?

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

X-G
Member #856
December 2000
avatar

s/class prototype/forward declaration of class x/

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Go to: