1

Related to a previous question, I have now the following one:

In the next scenery:

class B;

class A
{
   // stuff, methods and so on
   B b;
};

class B
{
   // stuff, methods and so on
   A a;
};

Here we have a circular dependence between A and B, but this code is ill-formed since B is an incomplete type. A solution is to change B by a pointer of B by means of a smart pointers for example. But adding pointer add complexity and resources spending unnecesarily since you don't need a pointer!

In the previous question I tried to avoid the use of pointers by means of templates, so I delay the instantation of the class at a point where both classes are defined, but I was incapable of doing it successfuly.

Is it impposible to avoid pointers? Are there well-known dessigns to avoid circular dependences?

Community
  • 1
  • 1
ABu
  • 10,423
  • 6
  • 52
  • 103
  • 6
    This wouldn't even make sense if it did compile. What you're saying is that an instance of `A` contains an instance of `B`, but an instance of `B` contains an instance of `A` too. You would need an infinite amount of memory and an infinite amount of time to create such an object. That is, both `A`'s constructor and `B`'s constructor would infinitely recurse. – cdhowie Apr 11 '13 at 17:05
  • 1
    Why are you trying to avoid pointers? – metalhead Apr 11 '13 at 17:06
  • 3
    You can use references as well. – dyp Apr 11 '13 at 17:09
  • Or `std::unique_ptr`, in order to avoid the nasty raw pointers. – Mihai Todor Apr 11 '13 at 17:10
  • 2
    Ask yourself, what is `sizeof(A)` or `sizeof(B)`? If you cannot answer the question with a finite number, you have an ill-formed class. That's when you should definitely consider using pointers and references. – kfmfe04 Apr 11 '13 at 17:18

3 Answers3

8

It is impossible to avoid some form of reference, for example pointers.

As you are trying it to do it, there is an infinite recursion in the definition. An A includes a B which includes and A, and so on for ever more. So, both classes would require infinite storage which is obviously nonsensical.

If you really have a model where A contains B and B contains A then these classes appear to be incapable of living without each other. In which case perhaps you only really have one class and not two.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I suppose in this case, it's "possible" since there's only one of each with no other fields. So it doesn't multiply. But yeah, it would need infinite memory in any other case. – Mysticial Apr 11 '13 at 17:06
  • @DyP It's about as useful as one can get when the question doesn't indicate *why* the OP wants do to this. – cdhowie Apr 11 '13 at 17:07
  • 4
    @DyP Posting that the OP's request is impossible is a valid way to answer on SO. – Mysticial Apr 11 '13 at 17:08
  • 1
    @DyP What's your answer for "is it impossible to avoid pointers?" I can't see any other answer. I defy you to come up with a fundamentally different answer to the question that was asked. – David Heffernan Apr 11 '13 at 17:08
  • @DyP So you think the answer is, you don't need to use pointers, you can use references? – David Heffernan Apr 11 '13 at 17:12
  • No. IIRC there's been a typo in your original answer, which you've corrected. Or I've misread it, for which I'd apologize. – dyp Apr 11 '13 at 17:13
7

The compiler has to figure out the space required for a B.

How does it do this? It works out that the space required is the size of an A.

But the size of an A is the size of a B. Back to square one and the compiler would have to loop forever to figure it out. Hence it does not compile.

The only solution is to break this cycle i.e use a pointer (smart or otherwise).

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
3

I don't think it's primarily a problem of the compiler (it cannot do that, though) but rather a problem in your design: A data member expresses ownership. If A has a data member of type B, then an instance of A owns an instance of B.

If the same holds for B, then you'll either get circular ownership (a owns b and b owns a) or a infinite series of a0 owns b0 owns a1 owns b1 .....

Therefore, you'll have to express for at least one of the two types that the instances don't own instances of the other type. You can do this in C++ using (smart) pointers or references, or passing the object to each member function of the class where it's required.

dyp
  • 38,334
  • 13
  • 112
  • 177