Круговая зависимость с унаследованным шаблоном класса

У меня проблема с круговой зависимостью. В основном у меня есть два класса, первый — это шаблонный класс, который использует некоторые функции из моего второго класса. Второй класс наследует от моего шаблона класса.

Ниже приведена упрощенная структура:

// Foo.h
#pragma once
#include "Bar.h"
template <class T> class Foo
{
public:
void DoSomething();
};

template <class T> void Foo<T>::DoSomething()
{
Bar::GetInstance()->LogEvent();
}//Bar.h
#pragma once
#include "Foo.h"
class Bar : public Foo<Bar>
{
public:
static Bar* GetInstance();
void LogEvent();
};//Bar.cpp
#include "Bar.h"
Bar* Bar::GetInstance()
{
// return instance of Bar singleton class
}

void Bar::LogEvent()
{
// log some event in a file
}

Теперь проблема в том, что когда я компилирую код, я получаю следующие ошибки в bar.h

Bar.h() : error C2504: 'Foo' : base class undefined
Bar.h() : error C2143: syntax error : missing ',' before '<'

Из того, что я могу сказать, это определенно проблема зависимости. Если я удалю вызов LogEvent из DoSomething и удалим ссылку «Bar.h» из Foo.h, проблема исчезнет.

Однако это не совсем решение, потому что Foo нужна функциональность, содержащаяся в Bar, и наоборот, bar наследуется от Foo и должна содержать ссылку на Foo.h.

Итак, как я могу решить эту проблему? Я просмотрел другие посты, касающиеся циркулярных ссылок, но мне не удалось решить проблему.

Спасибо

1

Решение

Исходя из кода, который вы разместили, foo.h не обязательно должен включать bar.h, и проблема исчезнет, ​​если этого не произойдет.

Важно то, что компилятор увидит Foo до того, как увидит Bar, и это может не произойти, если #include "bar.h" находится в верхней части foo.h (в зависимости от порядка foo.h и bar.h #includeв модулях потребления).

Тем не менее, если базовому классу необходимо принять определенный производный класс и вызвать его по имени, создается впечатление, что, возможно, существует проблема проектирования (будет ли работать виртуальная функция в базовом классе?). Но я не могу сделать такое суждение, не увидев всю картину.

Основываясь на комментариях ниже, я думаю, что вы можете решить непосредственную проблему, добавив третий файл:

// LogEvent.h

void LogEvent(...);

// LogEvent.cpp
#include "bar.h"
void LogEvent(...)
{
Bar::GetInstance()->LogEvent(...);
}

Затем измените foo.h следующим образом:

// Foo.h
#pragma once
#include "LogEvent.h"
template <class T> class Foo
{
public:
void DoSomething();
};

template <class T> void Foo<T>::DoSomething()
{
LogEvent(...);
}

Если нет и других проблем, это должно как минимум привести к компиляции.

0

Другие решения

Ваша проблема — определение функции:

template <class T> void Foo<T>::DoSomething()
{
Bar::GetInstance()->LogEvent();
}

Вам не нужно писать Bar имя класса здесь.

использовать:

template <class T> void Foo<T>::DoSomething()
{
T::GetInstance()->LogEvent();
}

Таким образом, когда вы пишете Foo<Bar> Bar заменит T,

Я проверил изменения с кодом, который вы опубликовали, и это сработало.

РЕДАКТИРОВАТЬ:

Ну, я нашел решение, используя Шаблонная специализация.

Добавьте это к вашему Foo.h:

template <>
class Foo<Bar>
{
public:
void DoSomething()
{
Bar::GetInstance()->LogEvent();
}
};

Это решит все ваши проблемы. Используя специализацию шаблона, если шаблон Foo создается с Bar введите в качестве аргумента, вы будете создавать экземпляр класса, определенного выше, вместо оригинала Foo,

Таким образом, вам больше не нужно беспокоиться о других классах, у которых нет метода GetInstance, И вы можете использовать этот подход, чтобы расширить свой код и использовать как можно больше специализаций Foo как ты хочешь.

0