1
votes

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

2
You are missing ; at the end of your class definitions.Mankarse
@Mankarse thanks for the spot. They are they in the actual code. I've edited the post.user3581793
On another note, does DoSomething() need to be in Foo()? If it requires Bar, why not put it in Bar?dlf
Maybe I missed something, but would T::GetInstance() work for your needs ? (at least the way you have it right now)?WhozCraig
@dlf Thanks for your comments. I've managed to compile to simplified code as well. So I'm a bit stumped. DoSomething() does need to be in Foo.user3581793

2 Answers

0
votes

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 #includeed 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.

0
votes

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.