Dynamic lists and polymorphism - c++

I have a map of type < lookup_ID, vector< parentclass*>> each location in the map holds a vector of type child class. The idea behind this system is the ability to add a child into its associated map using an add(parentclass*) function and it would be able to find its associated vector of child type. I tried using templates and casting to get the vector to recognized the type of child input into the add function with no luck. I don't want to have to declare an add function for each child of parent, and no matter how I did it I had to declare a function for each type. I could take them out of the map but then again I'm left with the issue of calling each child for any function I want to implement. Is their no way to match types of polymorphic structures into dynamically allocated lists?`
class Piece
{
public:
pieceType ID;
//...
}
class Infantry :
public Piece
{
public:
//...
};
class Artillery :
public Piece
{
public:
//...
};
//...
//In some other classes somewhere
std::map<pieceType, std::vector<Piece*>*> units;
units.emplace(Infantry_, new std::vector<Infantry*>);
units.emplace(Artillery_, new std::vector<Artillery*>);
//...
template<typename T>
std::vector<T*> operator+(std::vector<T*> a, Piece * b) {
a.push_back(static_cast<T*>(b));
return a;
}
add(Piece * piece){
units.at(piece->ID) = units.at(piece->ID) + piece;
}
Also I am aware that this code has some errors, it was more for an example of what i'm trying to say.

You have to use virtual funciton to get the ID for each child class
class Piece
{
public:
virtual PieceType ID() const = 0;
}
class Artillery
{
public:
virtual PieceType ID() const override { /* return your ID for Artillery */ }
}
class Infantery
{
public:
virtual PieceType ID() const override { /* return your ID for Infantery */ }
}

There's no relation between std::vector<Piece*> and either of std::vector<Infantry*> or std::vector<Artillery*>, so your map can only contain std::vector<Piece*>s.
This is for good reason. Imagine you have a std::vector<Infantry*>, and put a pointer to it into your std::map<pieceType, std::vector<Piece*>*>. You could then insert an Artillery * into that through the map.
Rather than exposing the std::vector<Piece*> directly, you could expose a (read only) view of it that casts to the particular subtype.
Using the ranges library
auto asInfantry = ranges::view::transform([](Piece * p){ return static_cast<Infantry *>(p); });
auto asArtillery = ranges::view::transform([](Piece * p){ return static_cast<Artillery *>(p); });
class PieceMap
{
std::map<pieceType, std::vector<Piece*>> units;
public:
auto Infantry() { return units.at(Infantry_) | asInfantry; }
auto Artillery() { return units.at(Artillery_) | asArtillery; }
};

Related

How to properly store inherited objects in std::map for good accessibility?

This is my first C++ related programming question. I consider myself a beginner in programming even though I have dealt with C++ in some ways for about half a year. My question yields at an inheritance problem that I recently faced in my work.
I have a class NodeMaster that should handle a container (right now a map) of different child objects inherited from the same base class NBase - accessing them, change data, ...
// Base class
class NBase
{
private:
int m_ID;
public:
NBase() { m_ID = 0; };
~NBase() {};
...
}
// Child class
class NSampler : NBase
{
private:
int m_ID;
std::string m_state;
public:
NSampler(std::string state) : {
m_ID = 1;
m_state = state;
}
...
}
The childs of NBase are 'registered' into the map via some arbitrary index:
#include "NBase.h"
class NodeMaster
{
private:
std::map<int, std::shared_ptr<sbr::NBase>> m_mpNodes;
public:
void register_node(int nIdx, std::shared_ptr<sbr::NBase> pNode)
{
this->m_mpNodes.insert(std::pair<int, std::shared_ptr<sbr::NBase>>(nIdx, pNode->clone()));
}
std::shared_ptr<sbr::NBase> get_node(int idx)
{
std::map<int, std::shared_ptr<sbr::NBase>>::iterator itr;
for (itr = this->m_mpNodes.begin(); itr != this->m_mpNodes.end(); ++itr) {
if (itr->first == idx) {
return itr->second;
}
}
}
I read about this problem on SO to imporve my solution step-by-step and also read about the issue of Object Slicing. Therefore I put the objects into a std::shared_ptr to guarantee the 'polymorphic behaviour' throughout the process. So far everything is good and I can add the Child class objects to the container via
std::shared_ptr<sbr::NSampler> sampler(std::make_shared<sbr::NSampler>("SAMPLER_INIT"));
NodeMaster nodeMater;
nodeMaster.register_node(sampler->get_ID(), sampler);
Now what gives me headaches is how to properly access the elements of m_mpNodes later in the code ... The nodeMaster itself is passed to another function by reference pre_process_lin(nodeMaster, m_Links) and to access the elements inside this function I expected to just write e.g. nodeMaster.get_node(1) but that does not return the inherited object 'NSampler' but rather 'NBase' ... to retrieve 'NSampler' I had to use a dynamic_cast for smart pointers:
nodeMaster.get_node(1); // NBase
...
std::shared_ptr<sbr::NSampler> test_sampler = std::dynamic_pointer_cast<sbr::NSampler>(nodeMaster.get_node(1)); // NSampler
To get this going I had to add a copy ctor to both the NBase and the NSampler (for using the covariance feature of C++) and considering that I deal with smart pointers I read this blog post to implement the copy ctor into the classes
// Base class
class NBase
{
private:
int m_ID;
public:
NBase() { m_ID = 0; };
~NBase() {};
public:
std::shared_ptr<NBase> clone() const
{
return std::shared_ptr<NBase>(this->clone_impl());
}
private:
virtual NBase* clone_impl() const = 0;
...
}
// Child class
class NSampler : NBase
{
private:
int m_ID;
std::string m_state;
public:
NSampler(std::string state) : {
m_ID = 1;
m_state = state;
}
public:
std::shared_ptr<NSampler> clone() const
{
return std::shared_ptr<NSampler>(this->clone_impl());
}
private:
virtual NSampler* clone_impl() const override
{
return new NSampler(*this);
}
...
}
With this setup I solve my problem of stacking together a bunch of inherited class objects into some container (map), but since this specific copy-ctor is called (in order to be able to add them to the container) the initial member variables (e.g. m_state) get overwritten after 're-calling' the objects from the map.
Is there a better way to wrap the process of inheritance, packing to container and unpacking without losing object data on the run due to the copy-ctor above?

C++ polymorphism: how to create derived class objects

I have an abstract base class called BaseStrategy. It contains one pure virtual function calculateEfficiency(). There are two classes ConvolutionStrategy and MaxPoolStrategy which derive from this base class and implement their own specific version of calculateEfficiency().
Here is some code:
class BaseStrategy {
public:
explicit BaseStrategy();
virtual ~BaseStrategy() = default;
private:
virtual double calculateEfficiency(mlir::Operation* op) = 0;
};
class ConvolutionStrategy : public BaseStrategy {
private:
double calculateEfficiency(mlir::Operation* op)
{
//some formula for convolution
return 1;
}
};
class MaxPoolStrategy : public BaseStrategy {
private:
double calculateEfficiency(mlir::Operation* op)
{
//some formula for MaxPool
return 1;
}
};
Now I have another class called StrategyAssigner. It has method calculateAllLayerEfficiencies() whose purpose is to iterate over all layers in a network. Depending on the type of layer there is a switch statement and should call the correct calculateEfficiency() depending on the layer type.
class StrategyAssigner final {
public:
explicit StrategyAssigner(){};
public:
void calculateAllLayerEfficiencies() {
// Logic to iterate over all layers in
// a network
switch (layerType) {
case Convolution:
// Call calculateEfficiency() for Convolution
break;
case MaxPool:
// Call calculateEfficiency() for MaxPool
break;
}
};
}
int main ()
{
StrategyAssigner assigner;
assigner.calculateAllLayerEfficiencies();
}
My question is, should I store references of objects Convolution and MaxPool in the class StrategyAssigner so that I can call the respective calculateEfficiency().
Or could you suggest a better way to call calculateEfficiency(). I don't really know how to create the objects (stupid as that sounds).
I can't make calculateEfficiency() static as I need them to be virtual so that each derived class can implemented its own formula.
If you included complete code I could give a more detailed answer, but you need to store BaseStrategy pointers that are initialized with derived class instances. Here's an example made from some of your code:
std::vector<std::unique_ptr<BaseStrategy>> strategies;
strategies.emplace_back(new ConvolutionStrategy);
strategies.emplace_back(new MaxPoolStrategy);
for (int i = 0; i < strategies.size(); ++i) {
std::unique_ptr<BaseStrategy>& pStrat = strategies[i];
pStrat->calculateEfficiency(...);
}
Note that this won't compile because I don't have enough details from the code you posted to make it so, but this shows how to exploit polymorphism in the way that you need.
Also, I used smart pointers for memory management; use these at your discretion.
You can indeed use runtime polymorphism here:
Declare ~BaseStrategy virtual (you are already doing it ;-)
If you are never going to instantiate a BaseStrategy, declare one of its methods as virtual pure, e.g. calculateEfficiency (you are already doing it as well!). I would make that method const, since it doesn't look it's going to modify the instance. And it will need to be public, because it will need to be accessed from StrategyAnalyser.
Declare calculateEfficiency as virtual and override in each of the subclasses. It could also be final if you don't want subclasses to override it.
I'd keep a std::vector of smart pointers to BaseStrategy at StrategyAssigner. You can use unique_ptrs if you think this class is not going to be sharing those pointers.
The key point now is that you create heap instances of the subclasses and assign them to a pointer of the base class.
class StrategyAssigner final {
public:
void addStrategy(std::unique_ptr<BaseStrategy> s) {
strategies_.push_back(std::move(s));
}
private:
std::vector<std::unique_ptr<BaseStrategy>> strategies_{};
};
int main()
{
StrategyAssigner assigner;
assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
}
Then, when you call calculateEfficiency using any of those pointers to BaseStrategy, the runtime polymorphism will kick in and it will be the method for the subclass the one that will be actually called.
class ConvolutionStrategy : public BaseStrategy {
private:
virtual double calculateEfficiency() const override {
std::cout << "ConvolutionStrategy::calculateEfficiency()\n";
return 10;
}
};
class MaxPoolStrategy : public BaseStrategy {
private:
virtual double calculateEfficiency() const override {
std::cout << "MaxPoolStrategy::calculateEfficiency()\n";
return 20;
}
};
class StrategyAssigner final {
public:
void calculateAllLayerEfficiencies() {
auto sum = std::accumulate(std::cbegin(strategies_), std::cend(strategies_), 0,
[](auto total, const auto& strategy_up) {
return total + strategy_up->calculateEfficiency(); });
std::cout << "Sum of all efficiencies: " << sum << "\n";
};
};
int main()
{
StrategyAssigner assigner;
assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
assigner.addStrategy(std::make_unique<MaxPoolStrategy>());
assigner.calculateAllLayerEfficiencies();
}
// Outputs:
//
// ConvolutionStrategy::calculateEfficiency()
// MaxPoolStrategy::calculateEfficiency()
// Sum of all efficiencies: 30
[Demo]

How to refer to instances of a class universally without type codes?

I was making a text based RPG in which I have an abstract Item class. From this Item class, I have the classes Weapon, Potion, Key, and Armor. The main character class, Protagonist uses these items and has a function doItemEffect(Item*). How do I implement doItemEffect(Item*) in a way that I refer to all items in universally? To better phrase my problem, if I wasn't clear, here is an example that uses a quite ugly solution.
class Protagonist
{
public:
void doItemEffect(Item* it)
{
switch(it->getType()) //<-- The type is an enum class
{
case ItemType::WEAPON:
attackOpponent(it.getAttackPower()); //If it is a weapon it would have this function
break;
case ItemType::POTION:
heal(it.getHealPower()); //If it is a weapon it would have this function
break;
case ItemType::KEY:
//..Code..
break;
case ItemType::ARMOR:
//More Code...
break;
}
};
And an example of two of the classes Potion and Weapon (The type of the class is a private variable stored in Item with a mutator method setType()):
class Potion : public Item
{
int healPower;
public:
Potion(std::string name, std::string description) : Item(name, description)
{
setType(ItemType::POTION);
}
//Code
};
Weapon:
class Weapon : public Item
{
int attackPower;
public:
Weapon(std::string name, std::string description) : Item(name, description)
{
setType(ItemType::WEAPON);
}
//Code
};
As you can see, this code relies on an class code and a switch in the Protagonist class. Because of this, this doesn't seem very object oriented or polymorphic. Thus, is there a way I could get what subclass a type of Item is, without having to use class codes? Or is there any other solution? The other problem with this snippet above is also that whenever I refer to an item outside of its class, I have to use the same switch statement for each type of item.
Create a virtual function use() in your Item class. Override this function from your derived classes to trigger the various actions (attack, heal, etc.), so that all your subclassed items have an abstract interface to use/apply them.
You can either use RTTI (e.g. dynamic_cast<>()) as an alternative to a dedicated type field:
class Protagonist
{
public:
void doItemEffect(Item* it)
{
Potion *potion = dynamic_cast<Potion *>(item);
Weapon *weapon = dynamic_cast<Weapon *>(item);
if (potion != nullptr) {
heal(potion->getHealPower());
}
else if (weapon != nullptr) {
attackOpponent(weapon->getAttackPower());
}
or use polymorphism by adding a virtual effect() class member function in the abstract Item class:
class Item {
// ...
public:
virtual void effect(Protagonist *) = 0;
// ...
};
and overriding it in the derived classes:
class Potion : public Item
{
// ...
public:
void effect(Protagonist *) override;
};
which has the drawback that your Potion class needs to know that it can be used by a Protagonist. To remedy this, double dispatch is often used. The problem being that C++ does not support double dispatch as a language feature. It can be simulated using the visitor pattern as such:
class Weapon;
class Potion;
class DispatchReceiver {
public:
virtual void effect(Weapon *) = 0;
virtual void effect(Potion *) = 0;
};
class Item {
// ...
public:
virtual void effect(DispatchReceiver *) = 0;
// ...
};
class Potion : public Item {
// ...
virtual void effect(DispatchReceiver *dr) override
{
dr->effect(this);
}
// ...
};
class Weapon : public Item {
// ...
public:
virtual void effect(DispatchReceiver *dr) override
{
dr->effect(this);
}
// ...
};
class Protagonist : public DispatchReceiver {
// ...
public:
void effect(Weapon *weapon) override
{
attackOpponent(weapon->getAttackPower());
}
void effect(Potion *potion) override
{
heal(potion->getHealPower());
}
void doItemEffect(Item* it)
{
it->effect(this);
}
};
Have a list of item types
template<class...Types>
struct type_list_t{};
using Items=type_list_t<Potion, Weapon, etc>;
this replaces your enum. You can write get index of type, and get type from (compile time) index. You can even write what I call a magic switch, mapping runtime (bounded) index to a compile time type via continuation passing style.
Next add a visit method to Item. It takes a index into the type list and then static casts this to the type of the child, then invokes a passed-in callback with the result of the cast.
Write function overloads that look like this:
void use_item( Protagonist*, Potion* );
void use_item( Protagonist*, Weapon* );
Then dispatch to it using visit in Protagonist.
Now you can simplify this by using a pre written variant.
template<class Base, class...Ts>
struct poly_variant:boost::variant<Ts...>{
using boost::variant<Ts...>::variant;
Base& base();
Base const& base() const;
};
now you can visit in Protagonist. A variant of this can be used if you want to make the storage be a pointer (or a smart pointer).
Write base() via apply visitor.

Who should have an iterator, my data class or the actual list inside that class?

Implementing iterators in real C++ application seems to be quite confusing to say the least. I am implementing this in a demo to understand iterators.
I have AudoDealer class, which has address etc and than it has the an actual list (in my case stl::list) that contains all the cars with that dealer. Now I want an iterator which can iterate through all the cars in that dealership.
First question is that should the concrete-iterator take in the AutoDealer class or the actual list inside this class which stores the cars? I would like it to take in AutoDealer class because that way it sort of have the ownership of the class and deals with it all together as oppose to an independent iterator which is posing only to an internal part of the structure but later seems better?
The 2nd question is that because I am using STL list class as my container, storing int currentItem does't make sense but I should be rather storing std::list<>iterator to traverse. Now I can't really get this iterator type to store to begin with! It will break the principle of exposing list implementation.
My code is below, it is still work in progress but everything is below and btw I am following gang of four book.
// IteratorDemo.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <list>
using namespace std;
template <class Object>
class Iterator
{
public:
virtual Object * first();
virtual Object * next();
virtual bool IsDone() const = 0;
virtual Object * currentItem() const = 0;
};
class Car
{
string make;
string model;
string price;
bool isTruck; // if true is truck, otherwise sedan (assume for this example)
};
//template <class Item>
class AutoDealer
{
public:
AutoDealer();
virtual ~AutoDealer();
// create iterator
//virtual Iterator<item> * CreateIterator() = 0;
virtual string GetDealerAddress()
{
return address;
};
virtual void SetDealerAddress(string addr)
{
address = addr;
}
virtual void SetNumberOfSedans() = 0;
virtual void SetNumberOfTrucks() = 0;
virtual Car * GetCar() = 0;
virtual void AddCar(Car car) = 0;
protected:
string address;
};
//template <class item>
class AutoDealerImpl : public AutoDealer
{
public:
AutoDealerImpl()
{
}
virtual ~AutoDealerImpl();
/* virtual Iterator<item> * CreateIterator()
{
return std::list<Car>::iterator;
}
*/
virtual void SetNumberOfSedans();
virtual void SetNumberOfTrucks();
virtual Car * GetCar();
virtual void AddCar(Car car)
{
carList.push_back( car );
}
protected:
std::list<Car> carList; // list implementation
};
template <class Object>
class AutoDealerIterator : public Iterator<Object>
{
public:
AutoDealerIterator( AutoDealer * theDealer )
{
// dealer = theDealer;
}
virtual Object * first()
{
}
virtual Object * next();
virtual bool IsDone() const = 0;
virtual Object * currentItem() const = 0;
protected:
AutoDealer * dealer;
int _currentItem; // this is an issue, it should be std::list<car>::iterator type here but how can I access that?
// I am not traversing a simple list but an STL list which already
// has its own iterator and I need that iterator to travese but how do I access it?
};
int _tmain(int argc, _TCHAR* argv[])
{
}
Update
I have another goal from this demo project which can bypass the previous questions.
As I have CAutoDealer which is simply the interface and than AutoDealerImpl which is concrete. The data members actually reside inside the concrete for encapsulation. How can I iterate through the data using the interface class?
My main objective is to iterate through std::list<Car> in my application. Should the AutoDealer have this responsibility or iterating this outside the main class is in line with OOP? My goal is a good Object Oriented Design and open to design patterns.
If you insist in having run-time polymorphic iterators you'd have your concrete iterator take a pair of std::list<Car>::iterators in a private constructor and you'd make your AutoDealerImpl a friend of your AutoDealerIterator so it can construct them:
class AutoDealerIterator
: public Iterator<Car>
{
friend class AutoDealer;
std::list<Car>::iterator d_begin;
std::list<Car>::iterator d_it;
std::list<Car>::iterator d_end;
AutoDealerIterator(std::list<Car>::iterator begin, std::list<Car>::end)
: d_begin(begin)
, d_it(begin)
, d_end(end)
{
}
public:
Car * first() final { this->d_it = this->d_begin; return this->next(); }
Car * next() final { return ++this->d_it == this->d_end? 0: &*this->d_it; }
bool IsDone() const final { return this->d_it == this->d_end; }
Object * currentItem() const final { return &*this->d_it; }
};
Creating the actual AutoDealerIterator object from an AutoDealer should be trivial.
Note that using a run-time polymorphic iterator is generally a bad idea: it doesn't quite work and is also quite likely to be relatively slow. Furthermore it seems that most processing of sequences actually has a concrete idea of the objects it is processing.

Is a big switch block unavoidable in C++ due to lack of reflection [duplicate]

This question already has answers here:
Is there a way to instantiate objects from a string holding their class name?
(12 answers)
Closed 9 years ago.
Assume I have a hierarchy of classes:
class Shape {
};
class Circle : public Shape {
}
class Square : public Shape {
}
... hundreds of other shapes continue on...
When given the name of a shape class as a string, I need to instantiate objects of that class.
In java, I can do something like this (pseudo code!)
Shape createShape(String name) {
return new Class.forName(name);
}
But in C++, I have to do this: (pseudo code!)
Shape * createShape(const string &name) {
if (name.compare("Circle") == 0) {
return new Circle();
}
else if (name.compare("Square") == 0) {
return new Square();
}
else if ... //hundreds of else if continues, one for each shape
}
Is there any better way in C++ to handle situation like this?
It's avoidable using the factory pattern, but you still need a bunch of boilerplate code to get off the ground. For example:
// Class factory functions -- these could also be inlined into their respective
// class definitions using a macro
Shape *createCircle() { return new Circle(); }
Shape *createSquare() { return new Square(); }
// etc.
// Create a map from type name to factory
typedef std::map<std::string, Shape *(*)()> ShapeFactoryMap;
ShapeFactoryMap factoryMap;
factoryMap["Circle"] = &createCircle;
factoryMap["Square"] = &createSquare;
// etc.
Then, when you want to instantiate an object, you can do this:
ShapeFactoryMap::iterator factory = factoryMap.find("Circle");
if (factory != factoryMap.end())
{
Shape *circle = factory->second(); // Creates a Circle instance
...
}
else
{
// Handle error
}
Whether this is better than just doing a series of if/else... string comparisons is not clear, since it depends on what exactly you're doing to be doing with this.
I second Adam Rosenfield's solution using maps. However, a lower level interface to get your higher level functionality is to use a dlsym() lookup.
Assume that your generic Shape interface lies in the file Shape.hpp and has the following form:
class Shape {
public:
virtual ~Shape () {}
//...virtual methods
virtual void draw () const = 0;
};
template <typename DERIVED>
class ShapeBridge : public Shape {
public:
static Shape * create () { return new DERIVED; }
};
struct ShapeFactory {
Shape * (*create) ();
};
Suppose you wanted to add a new shape dynamically by creating a new shared object, and then linking it dynamically into your existing running executable. Then, you can now create an abstract factory of sorts, which uses dynamic loading of shared objects to obtain the concrete factory functions:
#include <string>
#include <map>
#include <dlfcn.h>
struct ShapeCreator {
void *dlhandle_;
void *factory_;
ShapeCreator () : dlhandle_(0), factory_(0) {}
void open (std::string libname) {
dlhandle_ = dlopen(libname.c_str(), RTLD_LAZY);
factory_ = dlsym(dlhandle_, "factory");
}
void close () { if (dlhandle_) dlclose(dlhandle_); }
ShapeFactory * factory () const {
return static_cast<ShapeFactory *>(factory_);
}
static Shape * create (std::string name) {
static std::map<std::string, ShapeCreator> lookup;
static std::string dir = "./";
if (lookup[name].factory() == 0) {
lookup[name].open(dir + name + ".so");
}
return lookup[name].factory()->create();
}
};
Your shared object could have the following implementation:
// gcc -fPIC -shared -Wl,-export-dynamic -o Circle.so Circle.cpp -lc
#include "Shape.hpp"
#include <iostream>
class Circle : public ShapeBridge<Circle> {
public:
//..
void draw () const { std::cout << "I am a circle.\n"; }
};
extern "C" {
ShapeFactory factory = { Circle::create };
}
Then to dynamically create the shape:
Shape *s = ShapeCreator::create("Circle");
s->draw();
Of course, the example is a little more interesting if it actually obtained its name dynamically (like from a configuration file, or from a user input).
The main difference is that unlike Java, C++ doesn't have an in-built function like forName(String), which does the task for you. In C++ you have to implement it.
Now it's important how you do that stuff. The proposed way of switch/case is one way, which is straight forward but lengthy way. You can automate the things:
(1) First introduce an intermediate template class, which creates an object, so that you don't have to implement method for each and every class.
template<class Derived>
class ShapeCreator : public Shape { // This class automates the creations
public:
static Shape* Create () {
new Derived(); // Assuming that no-argument default constructor is avaialable
}
};
class Circle : public ShapeCreator<Circle> {
};
class Square : public ShapeCreator<Square> {
};
//... and so on
(2) Now inside the class Shape, introduce one static std::map, which holds a handle to every derived class.
class Shape {
public:
typedef std::map<std::sting, Shape* (*)()> ShapeMap;
static ShapeMap s_ShapeMap;
static Shape* Create (const std::string name) {
ShapeMap::iterator it = s_ShapeMap.find(name);
if(it == s_ShapeMap.end())
return 0;
it->second();
}
};
(3) Populating s_ShapeMap has to be done statically, you can choose to do it before the main() is called (be careful while doing this) or as the first function inside the main(). Use preprocessor trick to automate the things:
#define INIT(SHAPE) Shape::s_ShapeMap[#SHAPE] = &SHAPE::Create
Shape* InitializeShapeMap () {
INIT(Circle);
INIT(Square);
INIT(Triangle);
// ...
}
#undef INIT
Whenever any new shape is introduced, then just add it as an INIT inside the function.
C++ is a 'class based' language which means the structure of a class is only known at compile time. Hence you cannot generate a type at runtime.
It's better to avoid that sort of class instanciation unless you only know the class name at runtime.
If need to do that at large scale, have a look at third-party code generators such as jinja.
It'll help you create a factory off a template and a given mapping "string" -> "class name".
There's no way to do what you want the way it is in Java, but there are ways to make it slightly less painful than a giant switch statement. You will need some kind of factory. Personally I like to use something along these lines:
class ShapeBase
{
};
template<class TShape>
class Shape: public ShapeBase
{
public:
typedef TShape shape_type;
template< class TFactory >
static void registerClass(TFactory* factory)
{
factory->registerShape(shape_type::name(), [](){ return new shape_type(); });
}
};
class Circle: public Shape<Circle>
{
public:
static const char* name() { return "Circle"; }
};
class Square: public Shape<Square>
{
public:
static const char* name() { return "Square"; }
};
class ShapeFactory
{
private:
typedef std::function<ShapeBase*()> shape_creator;
std::map<std::string,shape_creator> _creators;
public:
ShapeFactory()
{
registerShapes();
}
void registerShapes()
{
Square::registerClass(this);
Circle::registerClass(this);
}
void registerShape( const std::string& name, shape_creator creator )
{
_creators[name] = creator;
}
ShapeBase* create(const std::string& name)
{
return _creators[name]();
}
};
int main( int argc, char** argv )
{
ShapeFactory factory;
ShapeBase* circle = factory.create("Circle");
ShapeBase* square = factory.create("Square");
return 0;
}
If you can get away with defining all of your Shape objects in an executable component or dynamic library, rather than a static library, then there are tricks that you can use to auto-register your classes with a singleton factory, but I think it's a better idea to do it this way and avoid the singleton.
There is no support for what you are asing in the language. Nevertheless you can use the following pattern to streamline your design:
class Shape
{
Shape *CreateShape(const char *name)
{
// Iterate single linked list of known derived classes.
Node *item = ListOfDerivedClasses;
while (item != NULL)
{
if (strcmp(item->name, name) == 0)
return item->factory();
item = item->next;
}
}
typedef Shape *CreateShapeInstance();
struct Node
{
char *name;
CreateShapeInstance *factory;
Node *next;
Node(char *n, CreateShapeInstance *f)
{
name = n; factory = f;
next = Shape::ListOfDerivedClasses;
Shape::ListOfDerivedClasses = this;
}
};
static Node *ListOfDerivedClasses;
};
class Circle : public Shape
{
static Shape *CreateInstance() { return new Circle(); }
}
static Shape::Node circle_info("Circle", Circle::CreateInstance);
The idea is that the single linked list that contains only static elements is created during initialization of static objects and it is never modified after that. This design allows adding derived classes without modifying the base class while CreateShape in the base class can create any derived class that registered itself in the list.