In the product I am working, one of very basic scenario is serialization of classes. Typically a class to be serialized calls serialization on its sub-component
e.g. if there is a class s.t. class
A{B;C;D;} then A.Pack will call pack
function on B,C,D.
Since there are many such classes, same pattern of code has to be duplicated over and over again.
Is it possible to encapsulate this behavior in a pattern (possibly using templates and inheritance)
The usual way of making a template do this is to use a type list:
#include <iostream>
// typelist definition
struct Empty {};
template < typename H, typename T = Empty >
struct Cons {
typedef H head;
typedef T tail;
};
// interfaces all items support
class IPack
{
public:
virtual void Pack() = 0;
};
// some packable items
class Fee : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fee\n";
}
};
class Fi : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fi\n";
}
};
class Fo : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fo\n";
}
};
class Fum : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fum\n";
}
};
// these two templates create a composite IPack from a list
// of the types of its parts
template <typename Types>
class PackList : public PackList<typename Types::tail>
{
protected:
typedef typename Types::head Item;
Item item;
public:
virtual void Pack() {
item.Pack();
PackList<typename Types::tail>::Pack();
}
};
template <>
class PackList<Empty> : public IPack
{
public:
virtual void Pack() {}
};
// FeeFiFoFum is a composite of four items
class FeeFiFoFum : public PackList<Cons<Fee,Cons<Fi,Cons<Fo,Cons<Fum> > > > >
{
};
// create a FeeFiFoFum and call pack on it, which calls pack on its parts
int main ()
{
FeeFiFoFum giant;
giant.Pack();
}
Proper implementations of composites created from type lists give you accessors for the members and so on, but this is enough to show how they works, and prints out that it packed Fee, Fi, Fo and Fum without specifying any behaviour.
One possible design that would help accomplish this is to use the Composite pattern. Your Component (to borrow from the Wikipedia drawing) is Packable, which would implement a Template Method Pack() that can do something like so:
GetChildren();
for each child:
child.Pack()
PackImpl();
PackImpl() is a pure virtual method in Packable, and all classes that inherit implement it appropriately. GetChildren() would return an STL container (possibly empty), for iteration. It can be implemented in Packable, along with a private member collection to store the child objects. Basically, you then inherit all the classes from Packable, implement PackImpl(), and you're done.
Note that this will cause issues if your inheritance hierarchy depends on the child pieces being members directly. If you've approached the problem in terms of aggregation, this should work well.
It's possible that the Visitor pattern may help.
http://en.wikipedia.org/wiki/Visitor_pattern
The idea of this is to separate the traversal logic (stepping through your objects) from the handling of each object. In this case, the per-object logic is serializing (encoding) a single object (or deserializing, of course). This should be fairly simple and minimally repetitive using normal OOP techniques.
Implementing the traversal and the Visitor-pattern specific code is annoying, but it's mostly boilerplate and should be a one-off thing.
One commenter wrote:
If you mean "is there a way I can write a template to automatically call a method on each of my member variables?", then the answer is no...
My (slightly evil) counter to that is yes, if the method is the destructor...
#include <iostream>
using namespace std;
bool Enable = false;
template <typename T>
class DS : public T {
public:
~DS() {
if (Enable) T::Serialize();
}
};
class A {
protected:
void Serialize() { cout << "A" << endl; }
};
class B {
protected:
void Serialize() { cout << "B" << endl; }
};
typedef DS<A> DSA;
typedef DS<B> DSB;
class C {
protected:
void Serialize() { cout << "C" << endl; }
private:
DSA a;
DSB b;
};
typedef DS<C> DSC;
int
main()
{
DSC c;
{
DSC c_copy = c;
Enable = true;
}
Enable = false;
}
The output is in reverse order, so to reconstruct objects you'd have to parse the serialized data and push each completed object on a stack. Composite objects would then know how many children to pop off of the stack. Or, of course, the serialization could go to an intermediate structure.
Another intriguing idea would be to use this hack once at startup (create and destroy only one special object) where the callbacks from the destructors would create a data structure that described the original object.
I also note that implicit copy constructors have potential for similar abuse, and possible in forward order...
Related
I am into a scenario that I have to (best thing I thought of) use virtual templated functions (for polymorphism), however, as far as I know, it is not possible.
I chose to 'use' virtual templated functions so I wouldnt need to use pointers and inheritance (for the observing part). My observable (subject) class is a Parser: it parses a XML file and is supposed to notify each observer about each node found. Every XML node is mapped into a class, for example:
// Maps the '?xml' tag
struct XML { int version; // other stuff... };
Instead, if I opted to use inheritance, I'd also have this class:
struct Node { // Probably blank? }
And then, the XML class would be as follows:
// Maps the '?xml' tag
struct XML : public Node { int version; // other stuff... };
I believe this would solve my problem, however I dont want to deal with pointers, since there would be a class (which I'm parsing the XML into) that has non-pointer attributes (nor I wish to make them pointers).
Here's how I implemented the observer pattern, with non-virtual templated functions. It does not work. Its just an example of how Id like it to be:
#include <iostream>
#include <vector>
enum Type { XML, // other xml tag types };
struct SomeXMLNode { int data; };
struct Observer {
// This is what Id like to make virtual
template<typename T>
void onObserved(T t, Type type)
{
std::cout << "[base] observing " << t.data << std::endl;
// 'Safely' cast t, according to the specified type
}
};
class Observable
{
public:
void attach(Observer* o) { observers.push_back(o); }
protected:
template<class Node>
void notify(Node node, Type type)
{
for (std::vector<Observer*>::iterator it = observers.begin(); it != observers.end(); it++) {
(*it)->onObserved(node, type);
}
}
Observable() {}
protected:
std::vector<Observer*> observers;
};
class Parser : public Observable
{
public:
void parse()
{
SomeXMLNode s;
s.data = 1234;
notify(s, Types::XML); // Notify all observers about 'some xml node' during the parsing
}
};
struct SomeLoadableClass : public Observer
{
void load()
{
Parser p;
p.attach(this);
p.parse();
}
template<typename T>
void onObserved(T t, Type type)
{
std::cout << "[derived] observing " << t.data << std::endl; // Will never(?) get called! :(
}
};
int main()
{
SomeLoadableClass m;
m.load();
return 0;
}
If inheritance were used, onObserved and notify functions could be changed to:
void onObserved(Node* node, Types type) { }
void notify(Node* node, Types type) { }
The 'Node' above is a struct, not the template I used in the other example.
Is the observer pattern even the best approach for this kind of task? Are there other choices without using inheritance? How could I get my derived class to dispatch the onObserved instead of the base class without declaring it virtual?
Since Parser derieves from Observable, the protected members should be accessible within Parser.
class Parser : public Observable
{
public:
void parse()
{
SomeXMLNode s;
s.data = 1234;
std::vector<Observer*>::iterator it = observers.begin();
for (;it != observers.end(); it++)
it->onObserved(s, Types::XML);
}
};
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();
}
};
I want to implement a class hierarchy for object dispatching. Different classes dispatch different elements, and each class can dispatch its element represented as different data types.
It is better understood through a (faulty) example. This is what I would like to have if virtual function templating was allowed:
class Dispatcher {
template <class ReturnType>
virtual ReturnType getStuffAs();
};
So that I can implement subclasses as:
class CakeDispatcher : public Dispatcher {
template <>
virtual Recipe getStuffAs(){ ... }
template <>
virtual Baked getStuffAs(){ ... }
};
class DonutDispatcher : public Dispatcher {
template <>
virtual Frozen getStuffAs(){ ... }
template <>
virtual Baked getStuffAs(){ ... }
}
So that I can do the following later on:
void function( Dispatcher * disp ) {
// Works for Donut and Cake, but result will be a different Baked object
Baked b = disp->getStuffAs<Baked>();
// works if disp points to a DonutDispatcher
// fails if it is a CakeDispatcher
// can be compiling/linking time error or runtime error. I don't care
Frozen f = disp->getStuffAs<Frozen>();
}
Requirements/constraints:
All possible return types are not known beforehand. That's why I "need" templates.
Each class can provide just some return types.
Classes must have a common ancestor, so that I can store objects through a pointer to parent class and invoke functions through this pointer.
EDIT: I CAN'T use C++11 features, but I CAN use boost library.
Things I've thought about, but are not a solution:
Obviously, virtual template functions
Curiously Recurring Template Pattern: breaks the condition of common ancestor
Using some kind of traits class containing the functionality of children classes, but it does not work because a non-virtual implementation in the parent class does not have access to this information
I could maybe store some typeid info in the parent class, passed by children on construction. This makes possible for the non-virtual parent dispatching method to dynamic-cast itself to the children type... but it appears to be ugly as hell, and I don't know if this can cause some kind cycle-referencing problem.
class Dispatcher {
private:
typeid(?) childType;
public:
Dispatcher(typeid childT) : childType(childT) {}
// NOT VIRTUAL
template <class ReturnType>
ReturnType getStuffAs()
{
// or something equivalent to this cast, which I doubt is a correct expression
return dynamic_cast<childType *>(this)->childGetStuffAs<ReturnType>();
}
};
Then child classes would implement childGetStuffAs functions, which are not virtual too.
I've read like 5-10 related questions, but none of the provided solutions seems to fit this problem.
Can any of you come up with a better solution?
Is there a standard pattern/technique for solving this problem?
EDIT: The real problem
In the real problem, I have physical models with properties that can be represented in multiple ways: functions, matrices, probability distributions, polynomials, and some others (for example, a non-linear system can be represented as a function but not as a a matrix, while a linear system can be transformed to both).
There are also algorithms which can use those models indistinctly, but they could require specific representations for some model features. That's the reason for the "getStuffAs" function. The whole think is a bit complicated --too much to explain it here properly--, but I can guarantee that in this context the interface is well defined: input, computation and output.
My intention was to make this possible assuming that the number of possible representations is fully defined beforehand, and making it possible to transform the products to already existing types/classes that cannot be modified.
However, i'm starting to realize that this is, indeed, not possible in a simple way --I don't want to write a library just for this problem.
#include <cstdio>
// as a type identifier
struct stuff {
virtual void foo() {}
};
template <typename T>
struct stuff_inh : stuff {
};
struct Dispatcher {
template <typename T>
T* getStuffAs() {
return (T*)((getStuffAsImpl( new stuff_inh<T>() )));
}
virtual void* getStuffAsImpl(void*) = 0;
virtual void type() {printf("type::dispatcher\n");}
};
struct Cake : public Dispatcher {
void* getStuffAsImpl(void* p) {
stuff* s = static_cast<stuff*>(p);
printf("cake impl\n");
if (dynamic_cast<stuff_inh<Cake>*>(s) == NULL) {
throw "bad cast";
}
return (void*)(new Cake());
}
virtual void type() {printf("type::Cake\n");}
};
struct Rabbit : public Dispatcher {
void* getStuffAsImpl(void* p) {
stuff* s = static_cast<stuff*>(p);
printf("rabbit impl\n");
if (dynamic_cast<stuff_inh<Rabbit>*>(s) != NULL) {
return (void*)(new Rabbit());
}
else if (dynamic_cast<stuff_inh<Cake>*>(s) != NULL) {
return (void*)(new Cake());
}
else {
throw "bad cast";
}
}
virtual void type() {printf("type::Rabbit\n");}
};
void foo(Dispatcher* d) {
d->getStuffAs<Cake>()->type();
d->getStuffAs<Rabbit>()->type();
}
int main() {
Rabbit* r = new Rabbit;
foo(r);
Cake* c = new Cake;
foo(c);
}
I an not sure about the correctness of this ugly solution, may it be helpful for you. >_<
deletion of resource is not coded for a clearer look.
My solution is a combination of recurring template and diamond inheritance.
At least it's working. :)
#include <iostream>
class Dispatcher
{
public:
template<class T>
T getStuff()
{
return T();
}
};
template<class T>
class Stuffer : public Dispatcher
{
public:
template<class TT=T>
TT getStuff(){
return reinterpret_cast<TT>(this);
}
};
class Cake{
public:
Cake(){}
void print()
{
std::cout << "Cake" << std::endl;
}
};
class Recipe
{
public:
Recipe(){}
void print()
{
std::cout << "Recipe" << std::endl;
}
};
class CakeRecipe : public Stuffer<Cake>, public Stuffer< Recipe >
{
public:
};
int main()
{
Dispatcher* cr = reinterpret_cast<Dispatcher*>(new CakeRecipe());
cr->getStuff<Cake>().print();
cr->getStuff<Recipe>().print();
getchar();
return 1;
}
I need to store a container of pointers to objects.
These objects have some common methods/attributes (interface) that I want to enforce (possibly at compile time) and use.
Example:
struct A{
void fly(){}
};
struct B{
void fly(){}
};
A a;
B b;
std::vector<some *> objects;
objects.push_back(&a);
objects.push_back(&b);
for(auto & el: objects)
el->fly();
The simpler solution would be A and B inherit a common base class like FlyingClass:
struct FlyingClass{
void fly(){}
};
struct A: public FlyingClass { ...
struct B: public FlyingClass { ...
and create a
std::vector<FlyingClass *> objects;
This will work and also enforce the fact that I can only add to objects things that can fly (implement FlyingClass).
But what if I need to implement some other common methods/attributes WITHOUT coupling them with the above base class?
Example:
struct A{
void fly(){}
void swim(){}
};
struct B{
void fly(){}
void swim(){}
};
And i would like to do:
for(auto & el: objects) {
el->fly();
...
el->swim();
...
}
More in general i would be able to call a function passing one of these pointers and access both the common methods/attributes, like:
void dostuff(Element * el){
el->fly();
el->swim();
}
I could try to inherit from another interface like:
struct SwimmingClass{
void swim(){}
};
struct A: public FlyingClass, public SwimmingClass { ...
struct B: public FlyingClass, public SwimmingClass { ...
But then what the container should contain?
std::vector<FlyingClass&&SwimmingClass *> objects;
Sure, i could implement SwimmingFlyingClass, but what if i need RunningClass etc.. This is going to be a nightmare.
In other words, how can I implement a pointer to multiple interfaces without coupling them?
Or there is some template way of rethinking the problem?
Even run time type information could be acceptable in my application, if there is an elegant and maintainable way of doing this.
It is possible to do this, in a pretty TMP-heavy way that's a little expensive at runtime. A redesign is favourable so that this is not required. The long and short is that what you want to do isn't possible cleanly without language support, which C++ does not offer.
As for the ugly, shield your eyes from this:
struct AnyBase { virtual ~AnyBase() {} }; // All derived classes inherit from.
template<typename... T> class Limited {
AnyBase* object;
template<typename U> Limited(U* p) {
static_assert(all<is_base_of<T, U>...>::value, "Must derive from all of the interfaces.");
object = p;
}
template<typename U> U* get() {
static_assert(any<is_same<U, T>...>::value, "U must be one of the interfaces.");
return dynamic_cast<U*>(object);
}
}
Some of this stuff isn't defined as Standard so I'll just run through it. The static_assert on the constructor enforces that U inherits from all of T. I may have U and T the wrong way round, and the definition of all is left to the reader.
The getter simply requires that U is one of the template arguments T.... Then we know in advance that the dynamic_cast will succeed, because we checked the constraint statically.
It's ugly, but it should work. So consider
std::vector<Limited<Flying, Swimming>> objects;
for(auto&& obj : objects) {
obj.get<Flying>()->fly();
obj.get<Swimming>()->swim();
}
You are asking for something which doesn't make sense in general, that's why there is no easy way to do it.
You are asking to be able to store heterogeneus objects in a collection, with interfaces that are even different.
How are you going to iterate over the collections without knowing the type? You are restricted to the least specific or forced to do dynamic_cast pointers and cross fingers.
class Entity { }
class SwimmingEntity : public Entity {
virtual void swim() = 0;
}
class FlyingEntity : public Entity {
virtual void fly() = 0;
}
class Fish : public SwimmingEntity {
void swim() override { }
}
class Bird : public FlyingEntity {
void fly() override { }
}
std:vector<Entity*> entities;
This is legal but doesn't give you any information to the capabilities of the runtime Entity instance. It won't lead anywhere unless you work them out with dynamic_cast and rtti (or manual rtti) so where's the advantage?
This is pretty much a textbook example calling for type erasure.
The idea is to define an internal abstract (pure virtual) interface class that captures the common behavior(s) you want, then to use a templated constructor to create a proxy object derived from that interface:
#include <iostream>
#include <vector>
#include <memory>
using std::cout;
struct Bird {
void fly() { cout << "Bird flies\n"; }
void swim(){ cout << "Bird swims\n"; }
};
struct Pig {
void fly() { cout << "Pig flies!\n"; }
void swim() { cout << "Pig swims\n"; }
};
struct FlyingSwimmingThing {
// Pure virtual interface that knows how to fly() and how to swim(),
// but does not depend on type of underlying object.
struct InternalInterface {
virtual void fly() = 0;
virtual void swim() = 0;
virtual ~InternalInterface() { }
};
// Proxy inherits from interface; forwards to underlying object.
// Template class allows proxy type to depend on object type.
template<typename T>
struct InternalImplementation : public InternalInterface {
InternalImplementation(T &obj) : obj_(obj) { }
void fly() { obj_.fly(); }
void swim() { obj_.swim(); }
virtual ~InternalImplementation() { }
private:
T &obj_;
};
// Templated constructor
template<typename T>
FlyingSwimmingThing(T &obj) : proxy_(new InternalImplementation<T>(obj))
{ }
// Forward calls to underlying object via virtual interface.
void fly() { proxy_->fly(); }
void swim() { proxy_->swim(); }
private:
std::unique_ptr<InternalInterface> proxy_;
};
int main(int argc, char *argv[])
{
Bird a;
Pig b;
std::vector<FlyingSwimmingThing> objects;
objects.push_back(FlyingSwimmingThing(a));
objects.push_back(FlyingSwimmingThing(b));
objects[0].fly();
objects[1].fly();
objects[0].swim();
objects[1].swim();
}
The same trick is used for the deleter in a shared_ptr and for std::function. The latter is arguably the poster child for the technique.
You will always find a call to "new" in there somewhere. Also, if you want your wrapper class to hold a copy of the underlying object rather than a pointer, you will find you need a clone() function in the abstract interface class (whose implementation will also call new). So these things can get very non-performant very easily, depending on what you are doing...
[Update]
Just to make my assumptions clear, since some people appear not to have read the question...
You have multiple classes implementing fly() and swim() functions, but that is all that the classes have in common; they do not inherit from any common interface classes.
The goal is to have a wrapper object that can store a pointer to any one of those classes, and through which you can invoke the fly() and swim() functions without knowing the wrapped type at the call site. (Take the time to read the question to see examples; e.g. search for dostuff.) This property is called "encapsulation"; that is, the wrapper exposes the fly() and swim() interfaces directly and it can hide any properties of the wrapped object that are not relevant.
Finally, it should be possible to create a new otherwise-unrelated class with its own fly() and swim() functions and have the wrapper hold a pointer to that class (a) without modifying the wrapper class and (b) without touching any call to fly() or swim() via the wrapper.
These are, as I said, textbook features of type erasure. I did not invent the idiom, but I do recognize when it is called for.
I am busy adding a generic observer mechanism to a legacy C++ application (using Visual Studio 2010, but not using .Net, so .Net delegates are out of the question).
In the design I want to separate the application-specific part as much as possible from the generic observer mechanism.
The most logical way of implementing observers seems this way:
class IDoThisObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
For every type of observer (IDoThisObserver, IDoThatObserver, ...) the arguments of the methods (handleDoThis, handleDoThat) are different.
What remains in a generic way of storing the observers, like this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (T &t) {m_observers.push_back(&t);}
private:
std::list<T*> m_observers;
};
Calling an observer can't be generalized since the arguments are different for every observer type.
An alternative way would be to 'pack' all arguments into one argument, like this:
struct DoThisInfo
{
DoThisInfo (int arg1, int arg2) : m_arg1(arg1), m_arg2(arg2) {}
int m_arg1;
int m_arg2;
};
And then define a more generic observer, like this:
template<typename T>
class IObserver
{
public:
void notify(const T &t) = 0;
};
And a collection of these observers would then become this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (IObserver<T> &obs) {m_observers.push_back(&obs);}
private:
std::list<IObserver<T>*> m_observers;
};
Now, much more logic can be centrally added to this ObserverContainer, including calling all observers. The 'initiator' of the call only needs to create and fill in the notification structure.
Classes that want to inherit from multiple kinds of observers, need to do it like this:
class MyObserver : public IObserver<NotifyThis>, public IObserver<NotifyThat>
{
...
};
Which of these approaches (observers with multiple explicit arguments or with one struct argument) seems the best? Are there any advantages or disadvantages to either of these approaches?
EDIT: I looked a bit further to alternative approaches, and the Slot/Signal approach seems another good candidate. Are there any important disadvantages in Slot/Signal that I should know of?
Why not just do:
class IObserver {
// whatever is in common
};
class IDoThisObserver : public IObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
class IDoThatObserver : public IObserver
{
public:
void handlDoThat(double arg1) = 0;
};
?
Then you have:
class ObserverContainer
{
public:
void addObserver (IObserver* t) {m_observers.push_back(t);}
private:
std::list<IObserver*> m_observers;
};
The design with the struct argument is definitely better as it allows for generic code to be written in the ObserverContainer. It's generally a good design practice to replace longish argument lists with objects that encapsulate the arguments and this is a good example of the payoff. By creating a more general abstraction for your notify method (with the struct you're defining notify as a method that takes a chunk of "data" whereas with the arg list you're defining a method that takes two numbers) you allow yourself to write generic code that uses the method and doesn't have to concern itself with the exact composition of the passed in chunk of data.
Have you looked into Boost.Signals? Better than to reimplement the wheel.
As for Parameters: Calling an observer/slot should conceptionally be the same as if you would call an ordinary function. Most SignalSlots-Implementations allow multiple Parameters, so use it. And please use different signals for different observer types, then there is no need to pass around data in Variants.
Two Disadvantages of the Observer-Pattern/SignalSlots i have seen:
1) Program flow is difficult or even impossible to understand by looking only at the source.
2) Heavily dynamic programs with lots of Observers/SignalSlots may encounter a "delete this"
Everything aside, i like Observers/SignalSlots more than subclassing and thus high coupling.
I don't think either of your approaches would fit your requirement as is. However a little modification using a DataCarrier containing the dataset passed across all the observers wherein each observer would know what to read would do the trick. The sample code below might clear it (note i have not compiled)
enum Type {
NOTIFY_THIS,
NOTIFY_THAT
};
struct Data {
virtual Type getType() = 0;
};
struct NotifyThisData: public Data {
NotifyThisData(int _a, int _b):a(_a), b(_b) { }
int a,b;
Type getType() { return NOTIFY_THIS; }
};
struct NotifyThatData: public Data {
NotifyThatData(std::string _str):str(_str) { }
std::string str;
Type getType() { return NOTIFY_THAT; }
};
struct DataCarrier {
std::vector<Data*> m_TypeData;
};
class IObserver {
public:
virtual void handle(DataCarrier& data) = 0;
};
class NotifyThis: public virtual IObserver {
public:
virtual void handle(DataCarrier& data) {
vector<Data*>::iterator iter = find_if(data.m_TypeData.begin(), data.m_TypeData.end(), bind2nd(functor(), NOTIFY_THIS);
if (iter == data.m_TypeData.end())
return;
NotifyThisData* d = dynamic_cast<NotifyThisData*>(*iter);
std::cout << "NotifyThis a: " << d->a << " b: " << d->b << "\n";
}
};
class NotifyThat: public virtual IObserver {
public:
virtual void handle(DataCarrier& data) {
vector<Data*>::iterator iter = find_if(data.m_TypeData.begin(), data.m_TypeData.end(), bind2nd(functor(),NOTIFY_THAT);
if (iter == data.m_TypeData.end())
return;
NotifyThatData* d = dynamic_cast<NotifyThatData*>(*iter);
std::cout << "NotifyThat str: " << d->str << "\n";
}
};
class ObserverContainer
{
public:
void addObserver (IObserver* obs) {m_observers.push_back(obs);}
void notify(DataCarrier& d) {
for (unsigned i=0; i < m_observers.size(); ++i) {
m_observers[i]->handle(d);
}
}
private:
std::vector<IObserver*> m_observers;
};
class MyObserver: public NotifyThis, public NotifyThat {
public:
virtual void handle(DataCarrier& data) { std::cout << "In MyObserver Handle data\n"; }
};
int main() {
ObserverContainer container;
container.addObserver(new NotifyThis());
container.addObserver(new NotifyThat());
container.addObserver(new MyObserver());
DataCarrier d;
d.m_TypeData.push_back(new NotifyThisData(10, 20));
d.m_TypeData.push_back(new NotifyThatData("test"));
container.notify(d);
return 0;
}
This way u need to modify only the enum if u add a new structure.
Also u can use boost::shared_ptr to handle the mess of pointers.
I wouldn't get the syntax right so I'm just going to list the declarations to illustrate the structures. A generic Observer could be made to expect a parameter that is either subclassed to specific forms of your required parameters or is struct including a horizontal mapping of all primitive parameters that will be required by your Observers. Then the ObserverContainer could function as an AbstractFactory and each subclass of the ObserverContainer could be DoThatObserverFactory and DoThisObserverFactory. The factory would build an observer and assign a configuration to the observer to tell it which parameter to expect.
class AbstractObserverFactory {...};
class DoThatObserverFactory : AbstractObserverFactory {...};
class DoThisObserverFactory : AbstractObserverFactory {...};
class ObserverParam {...};
class DoThatObserverParam : ObserverParam {...};
class DoThisObserverParam : ObserverParam {...};
class Observer;
class DoThisObserver : public Observer
{
public:
void handlDoThis(DoThisObserverParam);
};