4

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);
    };
};
Honza Bednář
  • 396
  • 4
  • 14
  • No since as I said it's not possible to declare nested class without defining the outer class. And early definition of the outer class causes another circular dependencies. – Honza Bednář Mar 12 '20 at 08:37
  • 2
    You'll have to make them separate classes. See https://stackoverflow.com/questions/951234/forward-declaration-of-nested-types-classes-in-c. If necessary, make them friends their "former" parent class. – AVH Mar 12 '20 at 08:40
  • You have to modularize the code more. it will create problem – Build Succeeded Mar 12 '20 at 08:53
  • Is there any reason you need those classes nested? – Rinat Veliakhmedov Mar 12 '20 at 12:31

3 Answers3

3

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);
}
Michel de Ruiter
  • 7,131
  • 5
  • 49
  • 74
QuentinUK
  • 2,997
  • 21
  • 20
3

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);
};
Caleth
  • 52,200
  • 2
  • 44
  • 75
1

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);
    ...
}
Gerhard Stein
  • 1,543
  • 13
  • 25