Okay, let me start off by saying that this is probably highly subjective and argumentative, and probably doesn't belong on here (feel free to close if the feeling is mutual). Having said that, I'm looking at some code, and I want to come to a standard approach for composition as it seems that different people have different styles - so, here are the styles I've seen so far (there may be more..) The particular composition problem I looking at is where a class B
owns an instance of class A
, but, A
needs to know that instance so that it can call methods of B
.
#include <iostream>
using namespace std;
namespace forward
{
class B;
class A
{
public:
A(B& b);
private:
B& inst;
};
class B
{
public:
B() : inst(*this) {}
void foo() { cout << "forward::B::foo()" << endl; }
private:
A inst;
};
A::A(B& b) : inst(b) { inst.foo(); }
}
namespace interface
{
struct IB
{
virtual void foo() = 0;
};
class A
{
public:
A(IB* b) : inst(b) { inst->foo(); }
private:
IB* inst;
};
class B : public IB
{
public:
B() : inst(this) {}
virtual void foo() { cout << "interface::B::foo()" << endl; }
private:
A inst;
};
}
namespace templated
{
template <typename IB>
class A
{
public:
A(IB& b) : inst(b) { inst.foo(); }
private:
IB& inst;
};
class B
{
public:
B() : inst(*this) {}
void foo() { cout << "templated::B::foo()" << endl; }
private:
A<B> inst;
};
}
int main(void)
{
forward::B b1;
interface::B b2;
templated::B b3;
return 0;
}
From this, I can see the following (not complete):
forward declarations Reduces need to include headers in headers, however you can't use the type that is forward declared in that header - i.e. the complete type has to be available when used.
interfaces Additional baggage (base class constructions, virtual function calls etc.)
templated I can't see any problems with this except compilation issues (i.e. ridiculous error messages etc.)
Now, I favour the templated approach - I think it's clean and has the advantage of being compile time enforced. So the crux of the question is, is there something technically wrong with this approach and if not, why would you take the other two approaches?
EDIT: I think the trivial example has not helped, in this particular instance, B is a resource manager, and own various components that are interlinked (A) - say for example various network connections etc. All the sub components can access each other through B - the whole system used to be a bunch of singletons... So the only reason that A knows of B is that it provides access to some other component that A needs...
It is interesting that most answers recommend forwarding, yet I still can't see why this is advantageous over the templated approach - is there some inherent fear of using templates in code other than for simple, generic functions?