I have two classes, Foo<T>
and Bar<T>
, derived from Base
. Each overrides a method virtual Base* convert(ID) const
, where ID
is an instance of a type that uniquely identifies a particular instantiation of Foo
or Bar
(pretend it's an enum
). The problem is that Foo::convert()
needs to be able to return a Bar
instance, and likewise Bar::convert()
needs to be able to instantiate Foo
. Since they're both templates, this results in a circular dependency between Foo.h
and Bar.h
. How do I resolve this?
Edit: A forward declaration does not work because the implementation of each method needs the constructor of the other class:
Foo.h
:
#include <Base.h> template<class T> class Bar; template<class T> class Foo : public Base { ... }; template<class T> Base* Foo<T>::convert(ID id) const { if (id == BAR_INT) return new Bar<int>(value); // Error. ... }
Bar.h
:
#include <Base.h> template<class T> class Foo; template<class T> class Bar : public Base { ... }; template<class T> Base* Bar<T>::convert(ID id) const { if (id == FOO_FLOAT) return new Foo<float>(value); // Error. ... }
The error is, naturally, "invalid use of incomplete type".
There are a couple of options to get rid of circular dependencies. For a longer chain, A -> B -> C -> D -> A , if one of the references is removed (for instance, the D -> A reference), the cyclic reference pattern is broken, as well. For simpler patterns, such as A -> B -> A , refactoring may be necessary.
The Mediator Pattern can also help to lift circular dependencies by encapsulating the bidirectional interaction of two or more objects. The downside of your current code is (besides the circular dependency), that whenever class A changes and also data persistence changes, you have to touch and modify class B.
A circular dependency is detected whenever two objects reference each other, in such a way that Power BI cannot process the objects. The details of why this happens are outlined in this article: Understanding Circular Dependencies in Tabular and PowerPivot – SQLBI.
Circular Dependencies in C++Its goal is to draw the “include” dependencies between classes in a C++ project. In particular, it allows to detect circular dependencies very easily or to check the architecture of a project.
What you need to do is seperate the class declarations from the implementation. So something like
template <class T> class Foo : public Base { public: Base* convert(ID) const; } template <class T> class Bar : public Base { public: Base* convert(ID) const; } template <class T> Base* Foo<T>::convert(ID) const {return new Bar<T>;} template <class T> Base* Bar<T>::convert(ID) const {return new Foo<T>;}
This way, you have complete class definitions when the functions are defined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With