Круговые зависимости C ++ с вложенным классом - PullRequest
3 голосов
/ 12 марта 2020

Я пытаюсь сгенерировать заголовочные файлы классов, которые восстанавливаю из того, что я разобрал с помощью IDA. Однако я получаю ошибки компиляции из-за циклических зависимостей. Для обычных классов я решил это, объявив их в отдельном файле, который я включил в качестве первого. Дело в том, что я не могу объявить внутренний класс без определения внешнего класса, что является проблемой.

Пример структуры класса:

Класс A:

#include "B.h"

class A {

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

Класс B :

#include "A.h"

class B {

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

Ответы [ 3 ]

2 голосов
/ 12 марта 2020

Использовать шаблоны.

    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){
}

например (здесь шаблон был перемещен вверх, поэтому тип не нужно указывать при каждом вызове функции.)

#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);
    }
2 голосов
/ 12 марта 2020

Вы можете заранее объявить Nested s в A и B, а затем определить их.

ah

class A {
public:
    class Nested;
};

Bh

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);
};
1 голос
/ 12 марта 2020

Когда компилятор читает ваш файл, он ожидает объявленные сущности.

Вы можете переслать объявление класса, но вы пропустите тип вложенных параметров.

То, что вы можете сделать, это иметь третий класс, который нарушает циклическую зависимость и наследует ваши вложенные классы:

class NestedBase {
};

Теперь используйте эту базу в вашем вложенном классе A:

#include "NestedBase.h"

class A {

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

И в вашем вложенном классе B а также:

#include "NestedBase.h"

class B {

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

Теперь с dynamic_cast в ваших реализациях методов вы можете преобразовать их в нужные вам типы и получить доступ ко всему, что вы объявили в своих вложенных классах.

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

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