Well, it is maybe not a really beautiful solution in the code, but it is really beautiful in the interface of your function. And it is also very efficient. It is ideal if the second is more important for you (for example, you are developing a library).
The trick is this:
A a = b.make();
is internally converted to a constructor of A, i.e. as if you had written A a(b.make());
.b.make()
should result a new class, with a callback function.Here is my minimal example. Check only the main()
, as you can see it is simple. The internals aren't.
From the viewpoint of the speed: the size of a Factory::Mediator
class is only 2 pointers, which is more that 1 but not more. And this is the only object in the whole thing which is transferred by value.
#include <stdio.h>
class Factory {
public:
class Mediator;
class Result {
public:
Result() {
printf ("Factory::Result::Result()\n");
};
Result(Mediator fm) {
printf ("Factory::Result::Result(Mediator)\n");
fm.call(this);
};
};
typedef void (*MakeMethod)(Factory* factory, Result* result);
class Mediator {
private:
Factory* factory;
MakeMethod makeMethod;
public:
Mediator(Factory* factory, MakeMethod makeMethod) {
printf ("Factory::Mediator::Mediator(Factory*, MakeMethod)\n");
this->factory = factory;
this->makeMethod = makeMethod;
};
void call(Result* result) {
printf ("Factory::Mediator::call(Result*)\n");
(*makeMethod)(factory, result);
};
};
};
class A;
class B : private Factory {
private:
int v;
public:
B(int v) {
printf ("B::B()\n");
this->v = v;
};
int getV() const {
printf ("B::getV()\n");
return v;
};
static void makeCb(Factory* f, Factory::Result* a);
Factory::Mediator make() {
printf ("Factory::Mediator B::make()\n");
return Factory::Mediator(static_cast<Factory*>(this), &B::makeCb);
};
};
class A : private Factory::Result {
friend class B;
private:
int v;
public:
A() {
printf ("A::A()\n");
v = 0;
};
A(Factory::Mediator fm) : Factory::Result(fm) {
printf ("A::A(Factory::Mediator)\n");
};
int getV() const {
printf ("A::getV()\n");
return v;
};
void setV(int v) {
printf ("A::setV(%i)\n", v);
this->v = v;
};
};
void B::makeCb(Factory* f, Factory::Result* r) {
printf ("B::makeCb(Factory*, Factory::Result*)\n");
B* b = static_cast<B*>(f);
A* a = static_cast<A*>(r);
a->setV(b->getV()+1);
};
int main(int argc, char **argv) {
B b(42);
A a = b.make();
printf ("a.v = %i\n", a.getV());
return 0;
}