Search code examples
c++recursionmutual-recursion

Understanding the "Mutual Recursion Issue" for the Return Type of Functions


I know the problem of recursive definition of types in C++ for member variables:

#include "B.h"
class A
{
    B b;
};

#include "A.h"
class B
{
    A b;
};

The compiler complains about this because it is not possible to allocate the memory in this recursive fashion.

What I don't understand is that this seems to apply to function definitions as well:

#include "B.h"
class A
{
    B foo();
};

#include "A.h"
class B
{
    A bar();
};

The compilers gives the same error:

error: ‘A’ does not name a type
error: ‘B’ does not name a type

Why is that? It does not make sense to me that the compiler needs to reserve space for the return type. Should I solve this problem with pointers and forward declaration? In my experience (coming from Java), it is quite common that programmers do these recursive definitions to design software. It seems so hard to realize this in C++.


Solution

  • As far as function definitions go, all you need is an appropriate forward declaration:

    class A;
    class B;
    
    class A
    {
        B foo();
    };
    
    class B
    {
        A bar();
    };
    

    This will compile with no issues. Feel free to chop this up into two separate header files, with an appropriate forward declaration instead of an #include.

    Note that the reason you can't declare class members the same way is because this will effectively have a class contain itself. Unfortunately, if that was possible, the end result would be a massive black hole that will swallow all life as we know it, and we certainly don't want that to happen...

    Anyway, the other point that you need to keep in mind is you are affected here by your Java background. Classes work fundamentally different in C++ than they do in Java, despite the deceivingly similar syntax. You're better off forgetting everything you know about how classes work in Java. Otherwise you'll keep getting off track, like that. In Java, a similar set of declarations does not result in a class effectively containing itself, but in C++ it does. This is because in Java every class instance is really a pointer to a class, but in C++ it is the class itself, in flesh and blood.

    In C++, the real equivalent to this kind of a recursive class declaration would be:

    class A
    {
        std::shared_ptr<B> b;
    };
    
    class B
    {
        std::shared_ptr<B> A;
    };
    

    (ignoring for the moment the requisite forward declarations that apply here, too).

    And this'll work in C++ equally well as it works in Java (the std::shared_ptr<> part is the equivalent of Java's object reference counting, sort-of). This is what's equivalent to your similar construct in Java.