Using C++ templates to create a class with custom components - c++

Let me explain what I am asking for by an example. Imagine I have a class for a car.
Now, the car may have a lot of extras:
4 doors instead of only 2
Automatic door locking
4 Wheel drive
I want to create the class with any combination of these options. Any of these options needs some data members. Imagine the class now looks like this:
class Car {
public:
bool FourDoors;
bool AutomaticDoorLocking;
bool FourWheelDrive;
Door doors[4]; //4 only needed if FourDoors=true
DoorLockingElectronic doorElectronic; //Only needed if AutomaticDoorLocking=true
TransmissionsShafts[4]; //4 only needed for FourWheelDrive=true
void lockDoors() {
if (AutomaticDoorLocking) {
doorElectronic.lockDoors();
} else {
// Do manual door locking
}
}
};
So far so good, but now I want to create a lot of cars, so many that memory gets critical. And I do not need most of the extras in most of those cars.
I could create a base class, and derive classes with those options enabled or disabled.
But I would have to create 2^{#extras} classes to create all possible combinations, with a lot of double code.
So I thought maybe templates could be used? (that is the question).
I can imagine having a flag template, and rewrite the lockDoors like this:
template<int flags>
void Car<flags>::lockDoors() {
if (flags | AutomicDoorLockingFlag) {
doorElectronic.lockDoors();
} else {
// Do manual door locking
}
}
Wonderful! But the class Car<0> still takes a lot of unnecessary space. So:
Can I somehow include or exclude class members depending on a template parameter?
Other Ideas how to deal with the situation are also welcome!

You want to use policy classes:
class FourDoorPolicy { Door m_doors[4]; ... };
class TwoDoorPolicy { Door m_doors[2]; ... };
class AutoDoorLockingPolicy { ... };
class ManualDoorLockingPolicy { void lockDoors(); ... };
class FourWheelDrivePolicy { TransmissionShafts m_shafts[4]; ... };
class TwoWheelDrivePolicy { TransmissionShafts m_shafts[2]; ... };
template <class DoorPolicy = TwoDoorPolicy,
class LockingPolicy = ManualDoorLockingPolicy,
class DrivePolicy = TwoWheelDrivePolicy>
class Car : public DoorPolicy, public LockingPolicy, public DrivePolicy
{
...
};
Put all the policy specific stuff (e.g. lockDoors() function) inside the policy classes rather than the Car class. The Car class inherits these, which is a form of composition (i.e. you are building all their functionality into the Car class).
Note that you should give all the policy classes a protected, non-virtual destructor so that they can only be instantiated as part of a derived class.
You then instantiate customised cars in the normal template manner:
Car<FourDoorPolicy, AutoDoorLockingPolicy, TwoWheelDrivePolicy> myCar;
Of course, you can use typedefs to help with this (and template aliases in C++0x will help a lot, too).
See: Policy-based Design

You probably should look into Policy-based design. Basically, it consists as externalizing behaviors in policy classes and instantiating a template car object with the appropriate policies. A policy class is responsible for the encapsulation of a given behavior.
From an implementation point of view : Car becomes a template where each type argument corresponds to a given policy (for example : DoorLockingPolicy). Your car template can then be "configured" depending the types you choose to instantiate it with : ManualDoorLockingPolicy or AutomaticDoorLockingPolicy.
template<class DoorLockingPolicy /*, class DoorsPolicy, ... */>
class Car : DoorLockingPolicy
{
public:
void lockDoors()
{
/* ... */
DoorLockingPolicy::lockDoors();
}
};
struct ManualDoorLockingPolicy
{
void lockDoors() { /* ... */ }
};
struct AutomaticDoorLockingPolicy
{
void lockDoors() { /* ... */ }
};
int main()
{
Car<ManualDoorLockingPolicy> car1;
Car<AutomaticDoorLockingPolicy> car2;
}
From a performance point of view, policy-based design is a great way to achieve "don't pay for what you don't use" :
Calls to the policy classes can be inlined and introduce no additional cost
The Car template can inherit privately from its policies and benefit from the empty base optimization.
Once again, Modern C++ Design (Andrei Alexandrescu) is a great read on this topic.

The problem as I see it is that you're trying to define a single class which is capable of representing all possible version of a "Car", meaning that each instance contains member data capable of representing all possible cars. This problem was solved eons ago by traditional inheritance.
Define the functionality common to all cars in the base class. Then derive specific classes which add functionality (and member variables which increase the memory footprint). You minimize your memory simply by instantiating the proper sub class. Each instance contains only the members important to that specific type of Car.

One possibility would be to introduce a feature class. The feature class would have some kind of a unique identifier (I've used int for the hell of it, but boost::uuids::uuid would be more preferable). It does nothing but define a feature of some sort:
class Feature
{
private:
int m_nUniqueID;
protected:
Feature(int _uniqueID) : m_nUniqueID(_uniqueID) {};
virtual ~Feature(){};
public:
const int& getUniqueID const {return(m_nUniqueID);};
}; // eo class Feature
From this, we can derive more concrete features:
class DoorsFeature : public Feature
{
private:
int m_nDoors;
public:
static const int UniqueId;
DoorsFeature(int numDoors) : Feature(UniqueId), m_nDoors(numDoors){};
virtual ~DoorsFeature(){};
void lockDoors() { /* lock the doors */ };
}; // eo class DoorsFeature
class ABSFeature : public Feature
{
public:
static const int UniqueId;
ABSFeature() : Feature(UniqueId){};
virtual ~ABSFeature(){};
}; // eo class ABSFeature
And onwards for any kind of feature that the car can have. Note I would not class wheels as a feature because, well, all cars have wheels although the number may differ. I am referring to various traits that can differ wildly such as electronic doors, ABS, etceteras. Suddenly, your car becomes a much simpler container:
class Car
{
private:
int m_nWheels;
std::string m_Colour;
std::vector<Feature> m_Features;
protected:
public:
Car();
~Car();
void addFeature(Feature& _feature) {m_Features.push_back(_feature);};
Feature getFeature(int _featureId) const;
void lockDoors()
{
DoorsFeature& doorsFeature(static_cast<DoorsFeature&>(getFeature(DoorsFeature::UniqueId)));
doorsFeature.lockDoors();
} // eo lockDoors
}; // eo class Car
Given this, you can also go a step further and introduced named feature-sets (much like the option packs you get from a dealer/manufacturer) that can be automatically applied to a car, or range of makes, models and series.
Obviously, I've left a lot out. You may want to pass a reference to the car to each feature, or do otherwise.

Try rewriting your code to use vector instead of arrays. You can use just the space you need, and it's easier too.
#include <vector>
#include <memory>
class Car
{
public:
int getDoorCount() { return doors.size(); }
bool isFourWheelDrive() { return transmissionShafts.size() == 4; }
bool areDoorsAutoLocking() { return automaticDoorLocking.get() != NULL; }
void lockDoors() {
if (automaticDoorLocking.get() != NULL) {
automaticDoorLocking->lockDoors();
} else {
// Do manual door locking
}
}
private:
std::vector<Door> doors;
std::vector<TransmissionsShafts> transmissionShafts;
std::auto_ptr<DoorLockingElectronic> automaticDoorLocking;
};
Notice how Car now supports hatchbacks (5 doors).

Related

Preferred way to understand object type at runtime

Consider I have a Plant class that has derived Fruit and Vegetable classes, and Fruit class has some more derived classes, like Orange and Apple, while Vegetable has derived Potato and Tomato. Assume, Plant has Plant::onConsume()=0; method:
class Plant
{
public:
virtual void onConsume(void)=0;
};
class Fruit:public Plant
{
};
class Orange:public Fruit
{
void onConsume(void)
{
// Do something specific here
}
};
class Apple:public Fruit
{
void onConsume(void)
{
// Do something specific here
}
};
class Vegetable:public Plant
{
};
class Potato:public Vegetable
{
void onConsume(void)
{
// Do something specific here
}
};
class Tomato:public Vegetable
{
void onConsume(void)
{
// Do something specific here
}
};
class Consumer
{
public:
void consume(Plant &p)
{
p.onConsume();
// Specific actions depending on actual p type here
// like send REST command to the remote host for Orange
// or draw a red square on the screen for Tomato
}
};
Suppose, I have a Consumer class with Consumer::consume(Plant) method. This "consume" method should perform different actions for different "Plants" instances/types, among calling Plant::onConsume() for any of "Plants". These action ain't directly related to the Plant class, require a lot of different additional actions and parameters, could literally be completely arbitrary, so cannot be implemented inside onConsume method.
What is the preferred method to implement this? As I understand, it is possible to implement some "Plant::getPlantType()=0" method, that would return plant type, but in this case I'm not sure what should it return. In case the returned value would be an enum, I'd need to change this enum each time I add a new derived class. And in any case, there's no control that multiple derived classes could return the same value.
Also, I'm aware there's a dynamic_cast conversion that returns nullptr if conversion could not be made, and typeid() operator that returns std::typeinfo (even with typeinfo::name()), which could be used in the switch() (it's just great for my case). But I'm afraid it could significally slow down the execution and make code heavier.
So, my question is, what is the preferred way in C++ to do that? maybe I just forgot about some simpler way to implement that?
A little update. Thank you for your explanations about inheritance, encapsulation etc! I supposed it's clear from my question, but it is not, I am sorry about that. So, please think about it, like I don't have an access to the whole Plant sources hierarchy, just need to implement this Consumer::onConsume(Plant). So I cannot add new specific methods in it. Or, also, it could be considered as a Plants library, that I have to write once, and make it usable for other devs. So, I could divide use cases/functionality into two parts: one that implemented "per class" in the Plant::onConsume() method, and second that is unknown yet and will differ depending on usage.
One option would be the visitor pattern, but this requires one function per type in some class. Basically you create a base class PlantVisitor with one Visit function per object type and pass add a virtual method to Plant that receives a PlantVisitor object and calls the corresponding function of the visitor passing itself as parameter:
class PlantVisitor
{
public:
virtual void Visit(Orange& orange) = 0;
virtual void Visit(Tomato& tomato) = 0;
...
};
class Plant
{
public:
virtual void Accept(PlantVisitor& visitor) = 0;
};
class Orange : public Plant
{
public:
void Accept(PlantVisitor& visitor) override
{
visitor.Visit(*this);
}
};
class Tomato : public Plant
{
public:
void Accept(PlantVisitor& visitor) override
{
visitor.Visit(*this);
}
};
This would allow you to do something like this:
class TypePrintVisitor : public PlantVisitor
{
public:
void Visit(Orange& orange) override
{
std::cout << "Orange\n";
}
void Visit(Tomato& tomato) override
{
std::cout << "Tomato\n";
}
};
std::vector<std::unique_ptr<Plant>> plants;
plants.emplace_back(std::make_unique<Orange>());
plants.emplace_back(std::make_unique<Tomato>());
TypePrintVisitor visitor;
for (size_t i = 0; i != plants.size(); ++i)
{
std::cout << "plant " << (i+1) << " is a ";
plants[i]->Accept(visitor);
}
Not sure the need for this does not indicate a design inefficiency though.
Btw: If you've got multiple visitors and do not necessarily want to implement logic for every single type in all of them, you could add default implementations in PlantVisitor that call the function for the supertype instead of specifying pure virtual functions.
Polymorphism is all about not having to know about a specific type. Usually your design is flawed if you discover having to detect a specific type explicitly.
At very first:
void Consumer::consume(Plant p)
does not work as intended! The Plant object is accepted by value, i. e. its bytes are copied one by one; however, only those of the Plant type, any others (those of derived types) are ignored and get lost within consume function – this is called object slicing.
Polymorphism only works with references or pointers.
Now assume you want to do something like the following (incomplete code!):
void Consumer::consume(Plant& p) // must be reference or pointer!
{
p.onConsume();
generalCode1();
if(/* p is apple */)
{
appleSpecific();
}
else if(/* p is orange */)
{
orangeSpecific();
}
generalCode2();
}
You don't want to decide yourself upon type, you let the Plant class do the stuff for you, which means you extend its interface appropriately:
class Plant
{
public:
virtual void onConsume() = 0;
virtual void specific() = 0;
};
The code of the consume function will now be changed to:
void Consumer::consume(Plant const& p) // must be reference or pointer!
{
p.onConsume();
generalCode1();
p.specific();
generalCode2();
}
You'll do so at any place you need specific behaviour (and specific is just a demo name, chose one that describes nicely what the function actually is intended to do).
p.onConsume();
generalCode1();
p.specific1();
generalCode2();
p.specific2();
generalCode3();
p.specific3();
generalCode4();
// ...
Of course you need now to provide appropriate implementations in your derived classes:
class Orange:public Fruit
{
void onConsume() override
{ }
void specific() override
{
orangeSpecific();
}
};
class Apple:public Fruit
{
void onConsume() override
{ }
void specific() override
{
appleSpecific();
}
};
Note the addition of override keyword, which protects you from accidentally creating overloaded functions instead actually overwriting in case of signature mismatch. It helps you, too, to locate all places of necessary changes if you discover having to change the function signature in the base class.

Abstract Factory in C++

I'm trying to understand the abstract factory pattern, here is my first approximation:
#include <iostream>
using namespace std;
class Soldier
{
public:
virtual void shoot()=0;
};
class Archer: public Soldier
{
public:
void shoot(){
cout<<"Archer shoot"<<endl;
}
};
class Rider: public Soldier
{
public:
void shoot(){
cout<<"Rider shoot"<<endl;
}
};
class AbstractFactory
{
public:
virtual Soldier* createArcher()=0;
virtual Soldier* createRider()=0;
};
class OrcFactory: public AbstractFactory
{
Soldier* createArcher()
{
return new Archer();
};
Soldier* createRider()
{
return new Rider();
};
};
class HumanFactory: public AbstractFactory
{
Soldier* createArcher()
{
return new Archer();
};
Soldier* createRider()
{
return new Rider();
};
};
class Game
{
public:
AbstractFactory* factory;
Game(AbstractFactory* factory):factory(factory){};
};
int main()
{
Game* game = new Game(new HumanFactory);
Archer* HumanArcher = static_cast <Archer*>(game->factory->createArcher());
Rider* humanRider = static_cast <Rider*>(game->factory->createRider());
HumanArcher->shoot();
humanRider->shoot();
return 0;
}
This is what I want to reproduce:
I have experience in programing but I'm newbie with patterns, not sure if this is the optimal solution or even if it's a good solution.
I'm reading about game engine architecture, but I'm stuck in this, not by errors, just doubt about the right solution for this exercise. The book has basic examples but not enough to understand it at all.
That's not exactly what makes an abstract factory. In your case, you would need a structure like this (the diagram ended up a bit too big, click the image to see it at its original resolution):
The idea is that you have a family of abstract classes or interfaces (here the units, archer, rider, etc.) and a family of concrete implementations for each type of factory (implementations for humans, implementations for orcs, etc.). The game uses only the abstract factory interface and does not need to care which are the actual types, while each implementation only needs to provide its own behaviour, allowing for easy extension.
As a side note, I used covariant return types in the diagram because C++ supports it (as opposed to, for example, C#) and it seems to make sense in this case (e.g. the method makeArcher in the base factory interface SoldierFactory is declared to return an Archer object, but the same method in OrcSoldierFactory returns a OrcArcher), but that is not strictly required by the pattern.

Database interface using inheritance and templates

I am trying to implement a simple database interface than can handle different types, including custom classes. I wanted to pick inheritance or templates but it seems that I used both with no good results.
Header file
enum class RECORD_TYPE
{
TYPE_LONG = 11,
TYPE_STRING = 12
//other types
};
// the reason I created this class is to use it as function member parent
class RecordType
{
public:
RecordType(RECORD_TYPE record_type) : record_type_(record_type) {}
RECORD_TYPE get_record_type()
{
return record_type_;
}
protected:
RECORD_TYPE record_type_;
};
template<class T>
class RecordType_t : public RecordType
{
public:
RecordType_t(T value, RecordType type) : RecordType(type), value_(value) {}
const T &get_value() const { return value_; }
protected:
T value_;
};
class RecordType_long : public RecordType_t<long>
{
public:
RecordType_long(long value) : RecordType_t(value, RECORD_TYPE::TYPE_LONG) {};
};
class RecordType_string : public RecordType_t<std::string>
{
public:
RecordType_string(std::string value) : RecordType_t(value, RECORD_TYPE::TYPE_STRING) {};
};
Usage
void add_record(const RecordType &record)
{
//here I need to know the type(string/long/custom) because the types have to be stored different
switch (record.get_record_type())
{
case RECORD_TYPE::TYPE_LONG:
//long x = record.get_value();
case RECORD_TYPE::TYPE_STRING:
//string x = record.get_value();
//then do something with these values
};
};
Database db;
RecordType_string str("test");
db.add_record(str);
RecordType_long lng(200);
db.add_record(lng)
My main problem (apart from the fact that I am pretty sure it's bad design) is that in the function add() I don't have access to get_value() member function so I can get the values of each type. Because, of course, in the parent class, if I create the get_value(), I won't know what type to return.
Can you suggest how to implement better this thing?
Thank you
P.S. I could dynamically cast from RecordType into RecordType_long/RecordType_string/etc but I read here that this is really really bad design.:)
The problem is that templates provide a polymorphic behavior which is orthogonal to the one provided by inheritance.
The former provides parametric polimorphism while the latter provides subtyping.
These two different types of polymorphism doesn't mix together in C++. Each template specialization is a different type which is orthogonal to the others specialization of the same template, which means that there is no is-a relationship between such types as you have with inheritance.
So your choices really depend on the design you intend to use. To let each kind of field save itself on the database for example you would need to let each instance manage its own serialization without the need of knowing which is who, for example:
class SerializableRecord
{
public:
virtual void save(Database& db) const;
}
class RecordType_long : private RecordType_t<long>, public SerializableRecord
{
public:
void save(Database& db) const override {
long value = get_value();
/* save it on database somehow */
}
}
In this way you can use polymorphism and templates together but for two different purposes, without the need of knowing which specific kind of record you are going to save, of course this also implies that you need to work with pointers or object slicing occurs.
Another solution would be to make Database::save templated and specialize for various types:
class Database {
public:
template<typename T> void save(const T& record);
}
template<> void Database::save<RecordType_t<long>>(const RecordType_t<long>& record) {
long value = record.get_value();
// ...
}
Actually you have many options, it really depends what you need to achieve and the complexity of the structure itself.

Referring to an object of a derived class from the base class of another (unrelated!) class in C++

If you can't understand the question title from the onset, it's not your fault - I couldn't think of a better description. Here is the explanation of the problem, which might be a bit lengthy, so apologies in advance.
In the initial version of my program, I had an Ecosystem class and an Individual class:
// Very simplified, for illustration purposes
class Ecosystem
{
protected:
// The int is just the ID of the individual.
std::map<int, std::shared_ptr<Individual> > individuals;
public:
Ecosystem();
void func(int _individual_id)
{
std::cout << "Individual's age: "
<< individuals[_individual_id]->get_age()
<< std::endl;
}
void routine(int _individual_id)
{
// Another function working via
// the pointers in individuals.
}
// More such functions...
};
class Individual
{
protected:
int age;
public:
Individual();
inline int get_age() const
{
return age;
}
};
The Ecosystem class contains dozens of functions, and I will add a lot more in the future.
I have now decided to split the Individual class into a base class and two derived classes, say TypeAIndividual and TypeBIndividual, because they each have members and attributes that the other one does not need (they also share a few members and attributes via the base class). So I have the base Individual class and two derived classes:
class TypeAIndividual : public Individual
{
protected:
// Data structures specific to individuals of type A
public:
TypeAIndividual();
};
class TypeBIndividual : public Individual
{
protected:
// Data structures specific to individuals of type B
public:
TypeBIndividual();
};
The problem is that the ecosystem now also needs to be split into TypeAEcosystem and TypeBEcosystem:
class Ecosystem
{
protected:
// Holding pointers to the base Individual class is pointless (pun not intended)
// std::map<int, std::shared_ptr<Individual> > individuals;
public:
Ecosystem();
// I want to keep func() in the base class
// because it only accesses attributes and
// members common to both classes derived
// from Individual.
void func(int _individual_id)
{
// Hmmmm...
// The pointers don't live in the Ecosystem class any more!
std::cout << "Individual's age: "
<< individuals[_individual_id]->get_age()
<< std::endl;
}
// OK to implement in each class
// derived from Ecosystem.
virtual void routine(int _individual_id) = 0;
};
class TypeAEcosystem : public Ecosystem
{
protected:
// Pointers to individuals
// of the corresponding type.
std::map<int, std::shared_ptr<TypeAIndividual> > individuals;
public:
TypeAEcosystem();
// Reimplementing routine() is OK
// because it does things specific to
// this individual type.
virtual void routine (int _individual_id)
{
// Operate on data structures particular
// to this type of individual.
}
};
class TypeBEcosystem : public Ecosystem
{
protected:
// Pointers to individuals
// of the corresponding type.
std::map<int, std::shared_ptr<TypeBIndividual> > individuals;
public:
TypeBEcosystem();
// Reimplementing routine() is OK
// because it does things specific to
// this individual type.
virtual void routine (int _individual_id)
{
// Operate on data structures particular
// to this type of individual.
}
};
TypeAEcosystem and TypeBEcosystem both use void func(int _individual_id), which needs to access individuals of the corresponding type. But the base class Ecosystem doesn't contain pointers to individuals any more because the std::maps are in each derived class and not in the base class.
My question is: how can I access the appropriate type of individual (TypeAIndividual or TypeBIndividual) while avoiding implementing separate void func(int _individual_id) in each class derived from Ecosystem? In other words, is there a way to keep func() in the base class so that when I change it, I don't have to make changes to the derived classes? In the actual program, there are dozens of functions like func() which take just an int as a parameter. Also, some of those functions take individual IDs from other structures in the Ecosystem class, so I can't simply pass a pointer to TypeAIndividual or TypeBIndividual.
Things I have considered
Merging TypeAIndividual and TypeBIndividual back into a common Individual class with all the data structures necessary for both derived classes. This strikes me as a particularly clumsy way of doing things, but at least it will work.
Making func() & Co. virtual and implementing them in TypeAEcosystem and TypeBEcosystem. This means that if I want to make a change in any of the functions, I have to change both implementations (= a maintenance nightmare).
Having only one Ecosystem class which holds std::maps of the two types of individuals, like this:
// Seems clunky...
class Ecosystem
{
protected:
// Note: The Ecosystem can contain
// one OR the other, but not both!
// One map will always be empty.
std::map<int, std::shared_ptr<TypeAIndividual> > type_a_individuals;
std::map<int, std::shared_ptr<TypeBIndividual> > type_b_individuals;
public:
Ecosystem();
void func(int _individual_id)
{
// Check what type of individuals we
// are working with and operate on the
// appropriate container.
if (type_a_individuals.size() > 0)
{
std::cout << "Individual's age: "
<< type_a_individuals[_individual_id]->get_age()
<< std::endl;
}
else
{
std::cout << "Individual's age: "
<< type_b_individuals[_individual_id]->get_age()
<< std::endl;
}
}
};
This would require inserting a check in every function, which is almost as bad in terms of maintainability as having the functions in separate classes.
Note: Although I would very much like to avoid passing pointers around, I would consider upcasting and/or downcasting as appropriate (as a last resort...) if it solves the problem.
Any suggestions are welcome!
Edit 1
Thank you all for the fantastic responses! As suggested by both amit and Chris, and looked at my Ecosystem class and sure enough, it was too bulky. I moved member functions around into other classes and now I'm down to four or five essential functions in the Ecosystem class. The Ecosystem class resides in a library and provides an interface for conducting experiments with individuals, but I don't want users to be able to manipulate Individuals and other classes directly, so I can't do away with it completely.
I liked all suggestions, there are some ingenious solutions. That being said, the one proposed by Chris grabbed my attention immediately for being very neat and allowing me to have a single Ecosystem class rather than three separate classes (base and two derived). The type of individual can be specified in a config file, and I can spawn multiple ecosystems from different config files within the same experiment. This is the accepted answer.
Thank you again everyone for the constructive input!
As I already said in my comment you could consider making Ecosystem a templated class and have one instance of an Ecosystem for each IndivualType.
template <class IndivualType>
class Ecosystem {
protected:
// The int is just the ID of the individual.
std::map<int, std::shared_ptr<IndivualType> > individuals;
public:
// ...
};
In case you need the Ecosystem to behave different for a given IndividualType, you can in addition explicitly specialize your Ecosystem like so:
template <>
class Ecosystem<SpecialIndividualType> {
protected:
// The int is just the ID of the individual.
std::map<int, std::shared_ptr<SpecialIndividualType> > individuals;
public:
// special implementation for EcoSystem for SpecialIndividualType
};
This probably will not be necessary, however it may be good to know.
Finally as you said the The Ecosystem class contains dozens of functions, and I will add a lot more in the future.
You may want to consider to split the functionality of your ecosystem into policies. I dont know your needs but just as an example:
template <class IndivualType, class SomePolicy1, class SomePolicy2>
class Ecosystem {
private:
const SomePolicy1 mSp1;
const SomePolicy2 mSp2;
protected:
// The int is just the ID of the individual.
std::map<int, std::shared_ptr<IndivualType> > individuals;
public:
Ecosystem (const SomePolicy1& sp1= SomePolicy1(), const SomePolicy2& sp2= SomePolicy2())) : mSp1(sp1), mSp2(sp2) {}
// ...
void func(int _individual_id)
mSp1.doSmth(_individual_id);
}
void func2(int _individual_id) {
mSp2.doSmth(_individual_id);
}
};
This is called "policy based design", you can find a lot of information about it on the web.
Of course there are other solutions as well, such as making the methods virtual as already mentioned. I would probably try both (depending on the time you have) and see what you feel most comfortable with.
Looking at the implementation details, I assume these. The eco system is a container/processor class of individuals. Looking at the interface the ids seems to be unique across different individuals, i.e. A invidual and B individual can not have same id.
If these are true, I will stick to one ecosystem class which defines the interface to access individuals, which can be stored in a map (base pointers*) since the ids are unique. Then ofc you can use dynamic casting from outside if you want to know which type is being requested and other manipulations can be done using the polymorphic interface of the individual classes. I also highly recommend you to use the implementation suggested by Herb Sutter http://www.gotw.ca/publications/mill18.htm#Notes because lot of experts highly acknowledge it for extendability among others.
You may add a virtual method in EcoSystem to retrieve generic TypeIndividual:
class EcoSystem
{
public:
void func(int _individual_id) {
std::cout << "Individual's age: "
<< get_individual(_individual_id).get_age()
<< std::endl;
}
virtual const TypeIndividual& get_individual(int _individual_id) const = 0;
virtual void routine(int _individual_id) = 0;
};
And for each subclass:
class TypeAEcosystem : public Ecosystem
{
protected:
// Pointers to individuals of the corresponding type.
std::map<int, std::shared_ptr<TypeAIndividual> > individuals;
public:
const TypeIndividual& get_individual(int _individual_id) const override
{
return *individuals.at(_id);
}
// Reimplementing routine() is OK
// because it does things specific to
// this individual type.
void routine (int _individual_id) override
{
// Operate on data structures particular
// to this type of individual.
}
};
Both derived Ecosystem's differ in their way to store and access the Individual's. That's a good case for making the Individual access behaviour virtual. With a dash of return type covariance, it looks quite fine :
struct Individual { void baseStuff() {} };
struct TypeAIndividual : Individual { void typeAStuff() {} };
struct Ecosystem {
void func(int id) {
individual(id).baseStuff();
}
virtual void routine(int id) = 0;
protected:
virtual Individual &individual(int id) = 0;
};
struct TypeAEcosystem : Ecosystem {
TypeAIndividual &individual(int id) override {
return *_individuals.at(id);
}
void routine(int id) override {
individual(id).typeAStuff();
}
private:
std::map<int, std::shared_ptr<TypeAIndividual>> _individuals;
};
Since the map and its accessor(s) are identical except for the type of individual, you can factor them out into an intermediary template base class :
template <class Individual>
struct DerivedEcosystem : Ecosystem {
Individual &individual(int id) override {
return *_individuals.at(id);
}
private:
std::map<int, std::shared_ptr<Individual>> _individuals;
};
struct TypeAEcosystem : DerivedEcosystem<TypeAIndividual> {
void routine(int id) override {
individual(id).typeAStuff();
}
};

oop - C++ - Proper way to implement type-specific behavior?

Let's say I have a parent class, Arbitrary, and two child classes, Foo and Bar. I'm trying to implement a function to insert any Arbitrary object into a database, however, since the child classes contain data specific to those classes, I need to perform slightly different operations depending on the type.
Coming into C++ from Java/C#, my first instinct was to have a function that takes the parent as the parameter use something like instanceof and some if statements to handle child-class-specific behavior.
Pseudocode:
void someClass(Arbitrary obj){
obj.doSomething(); //a member function from the parent class
//more operations based on parent class
if(obj instanceof Foo){
//do Foo specific stuff
}
if(obj instanceof Bar){
//do Bar specific stuff
}
}
However, after looking into how to implement this in C++, the general consensus seemed to be that this is poor design.
If you have to use instanceof, there is, in most cases, something wrong with your design. – mslot
I considered the possibility of overloading the function with each type, but that would seemingly lead to code duplication. And, I would still end up needing to handle the child-specific behavior in the parent class, so that wouldn't solve the problem anyway.
So, my question is, what's the better way of performing operations that where all parent and child classes should be accepted as input, but in which behavior is dictated by the object type?
First, you want to take your Arbitrary by pointer or reference, otherwise you will slice off the derived class. Next, sounds like a case of a virtual method.
void someClass(Arbitrary* obj) {
obj->insertIntoDB();
}
where:
class Arbitrary {
public:
virtual ~Arbitrary();
virtual void insertIntoDB() = 0;
};
So that the subclasses can provide specific overrides:
class Foo : public Arbitrary {
public:
void insertIntoDB() override
// ^^^ if C++11
{
// do Foo-specific insertion here
}
};
Now there might be some common functionality in this insertion between Foo and Bar... so you should put that as a protected method in Arbitrary. protected so that both Foo and Bar have access to it but someClass() doesn't.
In my opinion, if at any place you need to write
if( is_instance_of(Derived1) )
//do something
else if ( is_instance_of(Derived2) )
//do somthing else
...
then it's as sign of bad design. First and most straight forward issue is that of "Maintainence". You have to take care in case further derivation happens. However, sometimes it's necessary. for e.g if your all classes are part of some library. In other cases you should avoid this coding as far as possible.
Most often you can remove the need to check for specific instance by introducing some new classes in the hierarchy. For e.g :-
class BankAccount {};
class SavingAccount : public BankAccount { void creditInterest(); };
class CheckingAccount : public BankAccount { void creditInterest(): };
In this case, there seems to be a need for if/else statement to check for actual object as there is no corresponsing creditInterest() in BanAccount class. However, indroducing a new class could obviate the need for that checking.
class BankAccount {};
class InterestBearingAccount : public BankAccount { void creditInterest(): } {};
class SavingAccount : public InterestBearingAccount { void creditInterest(): };
class CheckingAccount : public InterestBearingAccount { void creditInterest(): };
The issue here is that this will arguably violate SOLID design principles, given that any extension in the number of mapped classes would require new branches in the if statement, otherwise the existing dispatch method will fail (it won't work with any subclass, just those it knows about).
What you are describing looks well suited to inheritance polymorphicism - each of Arbitrary (base), Foo and Bar can take on the concerns of its own fields.
There is likely to be some common database plumbing which can be DRY'd up the base method.
class Arbitrary { // Your base class
protected:
virtual void mapFields(DbCommand& dbCommand) {
// Map the base fields here
}
public:
void saveToDatabase() { // External caller invokes this on any subclass
openConnection();
DbCommand& command = createDbCommand();
mapFields(command); // Polymorphic call
executeDbTransaction(command);
}
}
class Foo : public Arbitrary {
protected: // Hide implementation external parties
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Foo specific fields here
}
}
class Bar : public Arbitrary {
protected:
virtual void mapFields(DbCommand& dbCommand) {
Arbitrary::mapFields();
// Map Bar specific fields here
}
}
If the base class, Arbitrary itself cannot exist in isolation, it should also be marked as abstract.
As StuartLC pointed out, the current design violates the SOLID principles. However, both his answer and Barry's answer has strong coupling with the database, which I do not like (should Arbitrary really need to know about the database?). I would suggest that you make some additional abstraction, and make the database operations independent of the the data types.
One possible implementation may be like:
class Arbitrary {
public:
virtual std::string serialize();
static Arbitrary* deserialize();
};
Your database-related would be like (please notice that the parameter form Arbitrary obj is wrong and can truncate the object):
void someMethod(const Arbitrary& obj)
{
// ...
db.insert(obj.serialize());
}
You can retrieve the string from the database later and deserialize into a suitable object.
So, my question is, what's the better way of performing operations
that where all parent and child classes should be accepted as input,
but in which behavior is dictated by the object type?
You can use Visitor pattern.
#include <iostream>
using namespace std;
class Arbitrary;
class Foo;
class Bar;
class ArbitraryVisitor
{
public:
virtual void visitParent(Arbitrary& m) {};
virtual void visitFoo(Foo& vm) {};
virtual void visitBar(Bar& vm) {};
};
class Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Parent specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitParent(*this);
}
};
class Foo: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Foo specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitFoo(*this);
}
};
class Bar: public Arbitrary
{
public:
virtual void DoSomething()
{
cout<<"do Bar specific stuff"<<endl;
}
virtual void accept(ArbitraryVisitor& v)
{
v.visitBar(*this);
}
};
class SetArbitaryVisitor : public ArbitraryVisitor
{
void visitParent(Arbitrary& vm)
{
vm.DoSomething();
}
void visitFoo(Foo& vm)
{
vm.DoSomething();
}
void visitBar(Bar& vm)
{
vm.DoSomething();
}
};
int main()
{
Arbitrary *arb = new Foo();
SetArbitaryVisitor scv;
arb->accept(scv);
}