Reputation: 404
Class A contains a pointer to abstract class B (only headers implemented):
// A.h
#include "B.h"
class A {
public:
A();
virtual ~A();
pointBto(B* b_); // { this.b = b_; }
private:
B* b;
}
// B.h
class B {
public:
B();
virtual ~B();
virtual void b_method() = 0;
}
Classes C and D inherit B.
// C.h
#include "B.h"
Class C : public B {
public:
C();
~C();
virtual b_method();
}
// D.h
#include "B.h"
Class D : public B {
public:
D();
~D();
virtual b_method();
}
Application reads a string and depending on that, creates a new object of class C or D and points b to the created object.
Note: I don't want to create an endless chain of
if (string_ == "C")
{
a_.pointBto(new C());
}
else if (string_ == "D")
{
a_.pointBto(new D());
}
else ...
Upvotes: 0
Views: 67
Reputation: 4095
If you want to avoid having an if else block (or some other similar centralized mechanism) which you extend every time you add a new derived class, you can have the derived types register themselves.
Check this thread for a trick on how to do it:
Is there a way to instantiate objects from a string holding their class name?
(note that with the solution given, the string doesn't need to be the same as the class name). Essentially you still have a map from a string to a factory function i.e.
map< std::string, std::function<B*()> >
the difference is that the code responsible for adding the callback to the map is where the derived class is defined.
Upvotes: 1
Reputation: 62563
What you are looking for is often refered to as 'virtual constructor'. I am usually not a fan of this construct, but it can be implemented using, for example, 'clone' idiom. Something like following:
struct Parent {
virtual Parent* clone(/*??? arg*/) = 0;
};
struct Child1 : Parent {
/*virtual */ Parent clone(/*??? arg*/) { return new Child1(/*arg*/); }
};
/* Child 2 */
Parent* make_parent(Choice arg) {
static std::map<Choice, Parent*> factory({{ch1, new Child1()}, {ch2, new Child2()}};
return factory.find(arg).second->clone(/**/);
}
The bigguest problem with that is that clone
arguments are aften reduced to some sort of the blob, which requires casting.
Upvotes: 1
Reputation: 40070
Simply create an std::map<std::string, std::function<B*(/*...*/)>>
:
static const std::map<std::string, std::function<B*(/*...*/)>> factory = {
{ "C", [](/*...*/){ return new C(/*...*/); },
{ "D", [](/*...*/){ return new D(/*...*/); },
};
a_.pointBto(factory[string_](/*arguments*/));
Upvotes: 1