C++ circular dependencies with nested class

Viewed 399

I'm trying to generate header files of classes I'm reconstructing from what I disassembled with IDA. However I'm getting compile errors due to circular dependencies. For regular classes I solved it by declaring them in a separate file I include as a first. The thing is I cannot declare inner class without definition of an outer class which is the problem.

An example class structure:

Class A:

#include "B.h"

class A {

public:
    class Nested {
    public:
        void foo(B::Nested &foo);
    };
};

Class B:

#include "A.h"

class B {

public:
    class Nested {
    public:
        void foo(A::Nested &foo);
    };
};
3 Answers

Use templates.

class A {
public:
    class Nested {
    public: 
        template<class B>
        void foo(typename B::Nested &fo);
    };
};

class B {
public:
    class Nested {
    public: 
        template<class A>
        void foo(typename A::Nested &fo);
    };
};

template<>
void A::Nested::foo<B>(B::Nested &fo){
}

template<>
void B::Nested::foo<A>(A::Nested &fo){
}

e.g. (Here the template has been moved up so the type doesn't have to be specified with each function call.)

#include <iostream>

class A {
public:
   template <class B>
   class Nested {
    public: 
        std::string name() const { return "a"; }

        void foo(typename B:: template Nested<A> &fo);
    };
};

class B {
public:
    template <class A>
    class Nested {
    public: 
        std::string name() const { return "b"; }

        void foo(typename A:: template Nested<B> &fo);
    };
};

template<>
void A::Nested<B>::foo(B::Nested<A> &fo){
    std::cout << "A::Nested " << fo.name() << '\n';
}

template<>
void B::Nested<A>::foo(A::Nested<B> &fo){
    std::cout << "B::Nested " << fo.name() << '\n';
}

int main()
{
    A::Nested<B> a;
    B::Nested<A> b;
    a.foo(b);
    b.foo(a);
}

You can forward declare the Nesteds in A and B, and define them afterward.

a.h

class A {
public:
    class Nested;
};

B.h

class B {
public:
    class Nested;
};

Nested.h

#include "A.h"
#include "B.h"

class A::Nested {
public:
    void foo(B::Nested &foo);
};

class B::Nested {
public:
    void foo(A::Nested &foo);
};

When a compiler reads your file it is expecting declared entities.

You can forward declare the class but you would be missing the Nested Parameter type.

What you can do is to have a third class which breaks the circular dependency and inherits to the your nested classes:

class NestedBase {
};

Now use this base in your A nested class:

#include "NestedBase.h"

class A {

public:
    class Nested : public NestedBase {
    public:
        void foo(NestedBase &foo);
    };
};

And in your B nested class as well:

#include "NestedBase.h"

class B {

public:
    class Nested : public NestedBase {
    public:
        void foo(NestedBase &foo);
    };
};

Now with dynamic_cast in your method implementations you can convert them to your desired types and access whatever you declared in your Nested Classes.

#include "A.h"
#include "B.h"

B::Nested::foo(NestedBase &foo)
{
    auto &fooA = dynamic_cast<A::Nested&>(foo);
    ...
}
Related