У меня проблема с круговой зависимостью. В основном у меня есть два класса, первый — это шаблонный класс, который использует некоторые функции из моего второго класса. Второй класс наследует от моего шаблона класса.
Ниже приведена упрощенная структура:
// 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.
Итак, как я могу решить эту проблему? Я просмотрел другие посты, касающиеся циркулярных ссылок, но мне не удалось решить проблему.
Спасибо
Исходя из кода, который вы разместили, 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(...);
}
Если нет и других проблем, это должно как минимум привести к компиляции.
Ваша проблема — определение функции:
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
как ты хочешь.