Reputation: 31
I'm having a circular dependency problem. Basically I have two classes, the first is a template class which uses some functionality from my second class. The second class inherits from my template class.
Below is a simplified structure:
// 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
}
Now the problem is when I complile the code I am getting the following errors in bar.h
Bar.h() : error C2504: 'Foo' : base class undefined
Bar.h() : error C2143: syntax error : missing ',' before '<'
From what I can tell this a definitely a dependency problem. If I remove the call to 'LogEvent' from within 'DoSomething', and remove reference "Bar.h" from Foo.h the issue goes away.
However it's not really a solution because Foo needs functionality contained with Bar, conversely bar inherits from Foo and needs to include a reference to Foo.h.
So - how can I resolve this problem? I have looked through the other posts regarding circular references but I haven't been able to solve the problem.
Thanks
Upvotes: 1
Views: 314
Reputation: 14360
Your problem is the definition of the function:
template <class T> void Foo<T>::DoSomething()
{
Bar::GetInstance()->LogEvent();
}
You don't need write Bar
class name here.
use:
template <class T> void Foo<T>::DoSomething()
{
T::GetInstance()->LogEvent();
}
That way, when you write Foo<Bar>
Bar
will replace T
.
I tested the change with the code you posted and it worked.
EDIT:
Well I found a solution using Template Specialization.
Add this to your Foo.h
:
template <>
class Foo<Bar>
{
public:
void DoSomething()
{
Bar::GetInstance()->LogEvent();
}
};
This solve all your problems. Using template specialization, if the template Foo
is instantiated with the Bar
type as argument, you will be instantiating the class defined above instead the original Foo
.
So, you don't have to worry any more about others classes don't have the method GetInstance
. And you can use this approach to expand your code and use as many specializations of Foo
as you want.
Upvotes: 0
Reputation: 9383
Based on the code you've posted, foo.h does not need to include bar.h, and the problem will go away if it doesn't.
The important thing is that the compiler see Foo before it sees Bar, and this may not happen if #include "bar.h"
is at the top of foo.h (depending on what order foo.h and bar.h are #include
ed in the consuming modules).
That said, if a base class needs to assume a specific derived class and call into it by name, it seems like there is probably a design issue (would a virtual function in the base work?). But I can't make that judgment without seeing whole picture.
Based on the comments below, I think you can solve the immediate problem by adding a third file:
// LogEvent.h
void LogEvent(...);
// LogEvent.cpp
#include "bar.h"
void LogEvent(...)
{
Bar::GetInstance()->LogEvent(...);
}
Then modify foo.h as follows:
// Foo.h
#pragma once
#include "LogEvent.h"
template <class T> class Foo
{
public:
void DoSomething();
};
template <class T> void Foo<T>::DoSomething()
{
LogEvent(...);
}
Unless there are other issues too, that should at least get you compiling.
Upvotes: 0