I'm trying to understand dynamic type casting.
How to properly implement the DrawAnimals and Talk To Animals functions using dynamic_cast?
DrawAnimals draws animals that can be drawn. Such animals implement the Drawable interface.
TalkToAnimals conducts a conversation with animals that can talk, that is, they implement the Speakable interface.
class Speakable {
public:
virtual ~Speakable() = default;
virtual void Speak(ostream& out) const = 0;
};
class Drawable {
public:
virtual ~Drawable() = default;
virtual void Draw(ostream& out) const = 0;
};
class Animal {
public:
virtual ~Animal() = default;
void Eat(string_view food) {
cout << GetType() << " is eating "sv << food << endl;
++energy_;
}
virtual string GetType() const = 0;
private:
int energy_ = 100;
};
class Bug : public Animal, public Drawable {
public:
string GetType() const override {
return "bug"s;
}
void Draw(ostream& out) const override {
out << "(-0_0-)"sv << endl;
}
};
class Cat : public Animal, public Speakable, public Drawable {
public:
void Speak(ostream& out) const override {
out << "Meow-meow"sv << endl;
}
void Draw(ostream& out) const override {
out << "(^w^)"sv << endl;
}
string GetType() const override {
return "cat"s;
}
};
void DrawAnimals(const std::vector<const Animal*>& animals, ostream& out) {
/*if (const Animal* r = dynamic_cast<const Animal*>(&animals)) {
} else if (const Bug* c = dynamic_cast<const Bug*>(&animals)) {
}*/
}
void TalkToAnimals(const std::vector<const Animal*> animals, ostream& out) {
//?
}
void PlayWithAnimals(const std::vector<const Animal*> animals, ostream& out) {
TalkToAnimals(animals, out);
DrawAnimals(animals, out);
}
int main() {
Cat cat;
Bug bug;
vector<const Animal*> animals{&cat, &bug};
PlayWithAnimals(animals, cerr);
}
I am going to explain for DrawAnimals and you can extended to other functions by yourself.
What you did here:
void DrawAnimals(const std::vector<const Animal*>& animals, ostream& out) {
/*if (const Animal* r = dynamic_cast<const Animal*>(&animals)) {
} else if (const Bug* c = dynamic_cast<const Bug*>(&animals)) {
}*/
}
Is plain wrong for several reasons:
animals is a vector
If you intended an individual element, then because &animals[i] (i = [0..animals.size()]) is a pointer to pointer (Animal**)
Because dynamic_cast<const Animal*>(animals[i]) (i = [0..animals.size()]) is the identity.
You need to work with each individual element of the vector:
void DrawAnimals(const std::vector<const Animal*>& animals, ostream& out) {
for (auto animal : animals) {
if (const Drawable* r = dynamic_cast<const Drawable*>(animal)) {
// this animal is Drawable
} else if (const Bug* c = dynamic_cast<const Bug*>(animal)) {
// this animal is a Bug
// only issue here: Bugs are also Drawable
// so this code will never be reached
}
}
}
Question: Why are some animals Drawable and other don't?
Related
I have this problem which I really struggle to even explain(as you can guess by the title) so I'll make it clear by an example
#include <iostream>
using namespace std;
class shape
{
public:
shape()
{
}
};
class triangle : public shape
{
public:
triangle()
{
}
};
class square : public shape
{
public:
square()
{
}
};
class shapeTeller
{
public:
shapeTeller() {}
void tellMeWhatShape(square s)
{
cout << "Hello, I'm a square\n";
}
void tellMeWhatShape(triangle t)
{
cout << "Hello, I'm a triangle\n";
}
void tellMeWhatShape(shape s)
{
cout << "Hello, I'm a generic shape\n";
}
};
int main()
{
shape sh;
triangle tr;
square sq;
shape shapeArray[3] = {sh, tr, sq};
shapeTeller tell;
for (auto &element : shapeArray)
{
tell.tellMeWhatShape(element);
}
}
this snippet of code prints three times "Hello, I'm a generic shape", while my desired output would be
"Hello, I'm a generic shape"
"Hello, I'm a triangle"
"Hello, I'm a square"
How can i achieve something like that, considering that I want the array to be of the superclass, and I want it to contains various subclasses?
I also want to make it clear that this is a simplified exhample but in the real implementation I can't use parametric polymorphism cause i want the shapeTeller class' methods to do completely different things.
Thanks a lot
Note: An array can only store a single type of object. A subtype of the object could be an entirely different size which is not something compatible with the way C++ stores arrays.
You could be using std::variant here to allow every array element to store one of several element types here:
class shapeTeller
{
public:
shapeTeller() {}
void tellMeWhatShape(square s)
{
std::cout << "Hello, I'm a square\n";
}
void tellMeWhatShape(triangle t)
{
std::cout << "Hello, I'm a triangle\n";
}
void tellMeWhatShape(shape s)
{
std::cout << "Hello, I'm a generic shape\n";
}
void tellMeWhatShape(std::variant<square, triangle, shape> const& s)
{
std::visit([this](auto const& shape)
{
tellMeWhatShape(shape);
},
s);
}
};
int main()
{
shape sh;
triangle tr;
square sq;
std::variant<square, triangle, shape> shapeArray[3] = { sh, tr, sq };
shapeTeller tell;
for (auto& element : shapeArray)
{
tell.tellMeWhatShape(element);
}
}
Alternatively dynamically allocate the shapes and implement the visitor pattern:
class shape;
class triangle;
class square;
struct Visitor
{
virtual void operator()(shape const&) = 0;
virtual void operator()(triangle const&) = 0;
virtual void operator()(square const&) = 0;
};
class shape
{
public:
virtual ~shape() = default;
shape()
{
}
virtual void Accept(Visitor& v) const
{
v(*this);
}
};
class triangle : public shape
{
public:
triangle()
{
}
void Accept(Visitor& v) const override
{
v(*this);
}
};
class square : public shape
{
public:
square()
{
}
void Accept(Visitor& v) const override
{
v(*this);
}
};
class shapeTeller
{
public:
shapeTeller() {}
void tellMeWhatShape(square s)
{
std::cout << "Hello, I'm a square\n";
}
void tellMeWhatShape(triangle t)
{
std::cout << "Hello, I'm a triangle\n";
}
void tellMeWhatShape(shape s)
{
std::cout << "Hello, I'm a generic shape\n";
}
};
int main()
{
auto sh = std::make_unique<shape>();
auto tr = std::make_unique<triangle>();
auto sq = std::make_unique<square>();
std::unique_ptr<shape> shapeArray[3] = { std::move(sh), std::move(tr), std::move(sq) };
shapeTeller tell;
struct ShapeTellerVisitor : Visitor
{
ShapeTellerVisitor(shapeTeller& teller)
: m_teller(teller)
{}
shapeTeller& m_teller;
virtual void operator()(shape const& s) override
{
m_teller.tellMeWhatShape(s);
}
virtual void operator()(triangle const& s) override
{
m_teller.tellMeWhatShape(s);
}
virtual void operator()(square const& s) override
{
m_teller.tellMeWhatShape(s);
}
};
ShapeTellerVisitor visitor{ tell };
for (auto& element : shapeArray)
{
element->Accept(visitor);
}
}
Note: You could implement Visitor with shapeTeller directly.
I have a base class Animal and a derived class Bird : Animal. I use a template class that will store vectors of pointers to either Animal or Bird objects. I want to overload the += operator in such a way that I can insert a new animal right in the Atlas, so m_length = m_length + 1, pages.push_back(animal), just to get the idea.
Here's my template class:
template <class T>
class Atlas2 {
public:
int m_length;
std::list<T> pages;
Atlas2() { m_length = 0; }
~Atlas2() {}
void adauga(T data);
T operator+=(const T& data) {
this->m_length++;
this->pages.push_back(data);
return *this;
};
};
And here's the Animal/Bird classes:
class Animal {
protected:
std::string m_name;
public:
Animal() {}
Animal(std::string name) : m_name{name} {}
virtual void set_name(std::string name) { m_name = name; }
virtual std::string get_name() { return m_name; }
virtual std::string regn() const { return "???"; }
virtual ~Animal() { cout << "Destructor animal" << '\n'; }
};
class Bird : public Animal {
public:
bird() : animal() {}
bird(std::string name) : Animal{name} {}
void set_name(std::string nume) { m_name = nume; }
std::string get_name() { return m_name; }
std::string regn() const override { return "pasare"; }
~bird() { cout << "destructor pasare" << '\n'; }
};
However, I can't figure this out. When I use the overloaded += operator in main() like this:
Pasare *c = new Pasare{"vulture"};
Atlas2<Animal *> Atlas;
Atlas += c;
It shows me an error, that it couldn't convert Atlas<Animal *> to <Animal*>.
How should I implement this correctly? Any tip?
Note: The template works fine, I can store in my list pointers to either Animal or Birds without problems, and access their specific methods. I just can't figure out the += part.
You should return Atlas2<T> & not T:
Atlas2<T>& operator+=(const T& data) {
this->m_length++;
this->pagini.push_back(data);
return *this;
};
The basic problem is that you've declared your operator+= as returning a T, but the return statement in it is return *this;, which is an Atlas2<T>.
If you change the return type to Atlas2<T> &, it should work. That's what you would normally want to return from an operator+= anyways, though with your use, it doesn't matter much as you're ignoring the returned value.
Could anyone tell me why i get a compiling error in the "setFlyBehaviour" and "setQuackBehaviour" of the Duck class? (error : "term does not evaluate to a function taking 1 arguments")
this is an example of a strategy pattern from Head First Design Patterns (which is in Java that i translated here in C++). I introduced a Wrapper pattern in order to manage memory. (the wrapper class i'm using is from Mark Joshi, Option Pricing and Design Patterns)
Thanks!!!!!
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string>
#include <map>
#include <exception>
#include <vector>
using namespace std;
template< class T>
class Wrapper
{
//Taken From Mark Joshi, Designs patterns and derivatives pricing
public:
Wrapper()
{ DataPtr =0;}
Wrapper(const T& inner)
{
DataPtr = inner.clone();
}
Wrapper(const Wrapper<T>& original)
{
if (original.DataPtr !=0)
DataPtr = original.DataPtr->clone();
else
DataPtr=0;
}
~Wrapper()
{
if (DataPtr !=0)
delete DataPtr;
}
Wrapper& operator=(const Wrapper<T>& original)
{
if (this != &original)
{
if (DataPtr!=0)
delete DataPtr;
DataPtr = (original.DataPtr !=0) ? original.DataPtr->clone() : 0;
}
return *this;
}
T& operator*()
{
return *DataPtr;
}
const T& operator*() const
{
return *DataPtr;
}
const T* const operator->() const
{
return DataPtr;
}
T* operator->()
{
return DataPtr;
}
private:
T* DataPtr;
};
/*****************************************************/
/***************** Interfaces ****************/
/*****************************************************/
class FlyBehaviour
{
private:
public:
virtual void fly() const = 0;
virtual FlyBehaviour* clone() const = 0;
};
class QuackBehaviour
{
private:
public:
virtual void quack() const = 0;
virtual QuackBehaviour* clone() const = 0;
};
/*****************************************************/
/***************** Implementations ***********/
/*****************************************************/
// -- FlyBehaviour
class FlyWithWings : public FlyBehaviour
{
public:
virtual void fly() const{
cout << "flying with wings" << endl;
}
virtual FlyBehaviour* clone() const {
return new FlyWithWings;
}
};
class FlyNoWay : public FlyBehaviour
{
public:
virtual void fly() const{
cout << "flying no way" << endl;
}
virtual FlyBehaviour* clone() const {
return new FlyNoWay;
}
};
// -- QuackBehaviour
class Quack : public QuackBehaviour
{
public:
virtual void quack() const{
cout << "Quacking here!" << endl;
}
virtual QuackBehaviour* clone() const{
return new Quack;
}
};
class Squeak : public QuackBehaviour
{
public:
virtual void quack() const{
cout << "Squeaking here!" << endl;
}
virtual QuackBehaviour* clone() const{
return new Squeak;
}
};
class Duck
{
private:
Wrapper<FlyBehaviour> flyBehaviour;
Wrapper<QuackBehaviour> quackBehaviour;
public:
void performQuack() const{
quackBehaviour->quack();
}
void performFly() const{
flyBehaviour->fly();
}
void setFlyBehaviour(const FlyBehaviour& mfly){
flyBehaviour(mfly);
}
void setQuackBehaviour(const FlyBehaviour& mquack){
quackBehaviour(mquack);
}
virtual void display() const{
}
};
class MallardDuck : public Duck
{
public:
virtual void display() const{
cout << "It looks like a Mallar" << endl;
}
};
class RedheadDuck : public Duck
{
public:
virtual void display() const{
cout << "It looks like a Redhead" << endl;
}
};
int main()
{
}
You were actually trying to call non-existent function instead of constructor.
There was also mistake in argument you were passing to setQuackBehaviour.
This should work:
void setFlyBehaviour(const FlyBehaviour& mfly){
flyBehaviour = mfly;
}
void setQuackBehaviour(const QuackBehaviour& mquack){
quackBehaviour = mquack;
}
It fails because Wrapper does not provide function call operator:
R T::operator ()(Arg1 a1, Arg2 a2, …)
And you are trying to make a call to Wrapper template:
flyBehaviour(mfly);
#werewindle like this ?
void reset(const QuackBehaviour& original){
if (DataPtr!= &original)
{
if (DataPtr!=0)
delete DataPtr;
DataPtr = (original.DataPtr !=0) ? original.DataPtr->clone() : 0;
}
}
I have the following class architecture:
class Animal
{
// ...
}
class Cat : public Animal
{
// ...
}
class Dog : public Animal
{
// ...
}
// + Several other derived classes
In another section of my code, I have a function that goes through a list of Animals and needs to perform specialized actions in the case of several of the derived classes and a default action otherwise. How can I handle this situation elegantly, given the following constraints:
I'd like to keep the new code outside of Animal and its derived
classes because of separation of concerns.
I'd like to avoid using a switch statement on types or enums as it feels very smelly.
Here's one way - use the concept-model idiom (my name):
#include <iostream>
#include <vector>
struct AnimalConcept {
virtual ~AnimalConcept() = default;
virtual void make_noise() const = 0;
};
// default case
void make_noise_for(const AnimalConcept&)
{
std::cout << "no noise" << std::endl;
}
template<class Model>
struct AnimalModel : AnimalConcept
{
void make_noise() const override {
make_noise_for(static_cast<const Model&>(*this));
}
};
// some models
struct Cat : AnimalModel<Cat>
{
};
struct Dog : AnimalModel<Dog>
{
};
struct Giraffe : AnimalModel<Giraffe>
{
};
// separation of concerns - specific overrides
void make_noise_for(const Cat&) {
std::cout << "meow\n";
}
void make_noise_for(const Dog&) {
std::cout << "woof\n";
}
// test
using namespace std;
int main(){
std::vector<std::unique_ptr<const AnimalConcept>> animals;
animals.emplace_back(new Cat);
animals.emplace_back(new Dog);
animals.emplace_back(new Giraffe);
for (const auto& p : animals) {
p->make_noise();
}
return 0;
}
expected output:
meow
woof
no noise
And here's another way to implement it (this one is nicer since it allows all animals to have unrelated interfaces):
#include <iostream>
#include <vector>
struct AnimalConcept {
virtual ~AnimalConcept() = default;
virtual void make_noise() const = 0;
};
// default case
template<class T>
void make_noise_for(const T&)
{
std::cout << "this animal makes no noise" << std::endl;
}
template<class Model>
struct AnimalModel : AnimalConcept
{
template<class...Args>
AnimalModel(Args&&...args)
: _model { std::forward<Args>(args)... }
{}
private:
void make_noise() const override {
make_noise_for(_model);
}
Model _model;
};
// some models
struct Cat
{
Cat(std::string name)
: _name { std::move(name) }
{}
const std::string& name() const {
return _name;
}
private:
std::string _name;
};
struct Dog
{
Dog(std::string name, int age)
: _name { std::move(name) }
, _age { age }
{}
const std::string& name() const {
return _name;
}
int age() const {
return _age;
}
private:
std::string _name;
int _age;
};
struct Giraffe
{
};
// separation of concerns - specific overrides
void make_noise_for(const Cat& c) {
std::cout << c.name() << " says meow\n";
}
void make_noise_for(const Dog& d) {
std::cout << "the dog called " << d.name() << " who is " << d.age() << " years old says woof\n";
}
// test
using namespace std;
int main(){
std::vector<std::unique_ptr<const AnimalConcept>> animals;
animals.emplace_back(new AnimalModel<Cat> { "felix" });
animals.emplace_back(new AnimalModel<Dog> { "fido", 2 });
animals.emplace_back(new AnimalModel<Giraffe>);
for (const auto& p : animals) {
p->make_noise();
}
return 0;
}
expected output:
felix says meow
the dog called fido who is 2 years old says woof
this animal makes no noise
You can use a combination of the following to get type based dispatch.
Provide for every class to return a type ID associated with it.
Provide a virtual function in the base class to get the type ID associated with an object.
Provide a way for registration of functions based on type ID.
When the time comes for execution of the top level function, search for a registered function given an animal's type ID. If a function is registered, call it. Otherwise, use the default function.
// Implement this function in a .cpp file.
int getNextTypeID()
{
static int typeID = 0;
return ++typeID;
}
class Animal
{
virtual int getTypeID();
};
class Cat : public Animal
{
static int getID()
{
static int typeID = getNextTypeID();
}
virtual int getTypeID()
{
return getID();
}
};
class Dog : public Animal
{
static int getID()
{
static int typeID = getNextTypeID();
}
virtual int getTypeID()
{
return getID();
}
};
foo.h:
typedef void (*AnimalFunction)(Animal& a);
int registerAnimalFunctor(int typeID, AnimalFunction f);
void foo(Animal& a);
foo.cpp:
typedef std::map<int, AnimalFunction> AnimalFunctionMap;
AnimalFunctionMap& getAnimalFunctionMap()
{
static AnimalFunctionMap theMap;
return theMap;
}
int registerAnimalFunctor(int typeID, AnimalFunction f)
{
getAnimalFunctionMap()[typeID] = f;
return 0;
}
void defaultAnimalFunction(a)
{
// Default action
}
void foo(Animal& a)
{
AnimalFunctionMap& theMap = getAnimalFunctionMap();
AnimalFunctionMap::iterator iter = theMap.find(a.getTypeID());
if ( iter != theMap.end() )
{
iter->second(a);
}
else
{
defaultAnimalFunction(a);
}
}
cat_foo.cpp:
void CatFunction(Animal& a)
{
// Cat action.
}
int dummy = registerAnimalFunctor(Cat::getID(), CatFunction);
dog_foo.cpp:
void DogFunction(Animal& a)
{
// Dog action.
}
int dummy = registerAnimalFunctor(Dog::getID(), DogFunction);
I realize that I'll most likely get a lot of "you shouldn't do that because..." answers and they are most welcome and I'll probably totally agree with your reasoning, but I'm curious as to whether this is possible (as I envision it).
Is it possible to define a type of dynamic/generic object in C++ where I can dynamically create properties that are stored and retrieved in a key/value type of system? Example:
MyType myObject;
std::string myStr("string1");
myObject.somethingIJustMadeUp = myStr;
Note that obviously, somethingIJustMadeUp is not actually a defined member of MyType but it would be defined dynamically. Then later I could do something like:
if(myObject.somethingIJustMadeUp != NULL);
or
if(myObject["somethingIJustMadeUp"]);
Believe me, I realize just how terrible this is, but I'm still curious as to whether it's possible and if it can be done in a way that minimizes it's terrible-ness.
C++Script is what you want!
Example:
#include <cppscript>
var script_main(var args)
{
var x = object();
x["abc"] = 10;
writeln(x["abc"]);
return 0;
}
and it's a valid C++.
You can do something very similar with std::map:
std::map<std::string, std::string> myObject;
myObject["somethingIJustMadeUp"] = myStr;
Now if you want generic value types, then you can use boost::any as:
std::map<std::string, boost::any> myObject;
myObject["somethingIJustMadeUp"] = myStr;
And you can also check if a value exists or not:
if(myObject.find ("somethingIJustMadeUp") != myObject.end())
std::cout << "Exists" << std::endl;
If you use boost::any, then you can know the actual type of value it holds, by calling .type() as:
if (myObject.find("Xyz") != myObject.end())
{
if(myObject["Xyz"].type() == typeid(std::string))
{
std::string value = boost::any_cast<std::string>(myObject["Xyz"]);
std::cout <<"Stored value is string = " << value << std::endl;
}
}
This also shows how you can use boost::any_cast to get the value stored in object of boost::any type.
This can be a solution, using RTTI polymorphism
#include <map>
#include <memory>
#include <iostream>
#include <stdexcept>
namespace dynamic
{
template<class T, class E>
T& enforce(T& z, const E& e)
{ if(!z) throw e; return z; }
template<class T, class E>
const T& enforce(const T& z, const E& e)
{ if(!z) throw e; return z; }
template<class Derived>
class interface;
class aggregate;
//polymorphic uncopyable unmovable
class property
{
public:
property() :pagg() {}
property(const property&) =delete;
property& operator=(const property&) =delete;
virtual ~property() {} //just make it polymorphic
template<class Interface>
operator Interface*() const
{
if(!pagg) return 0;
return *pagg; //let the aggregate do the magic!
}
aggregate* get_aggregate() const { return pagg; }
private:
template<class Derived>
friend class interface;
friend class aggregate;
static unsigned gen_id()
{
static unsigned x=0;
return enforce(++x,std::overflow_error("too many ids"));
}
template<class T>
static unsigned id_of()
{ static unsigned z = gen_id(); return z; }
aggregate* pagg;
};
template<class Derived>
class interface: public property
{
public:
interface() {}
virtual ~interface() {}
unsigned id() const { return property::id_of<Derived>(); }
};
//sealed movable
class aggregate
{
public:
aggregate() {}
aggregate(const aggregate&) = delete;
aggregate& operator=(const aggregate&) = delete;
aggregate(aggregate&& s) :m(std::move(s.m)) {}
aggregate& operator=(aggregate&& s)
{ if(this!=&s) { m.clear(); std::swap(m, s.m); } return *this; }
template<class Interface>
aggregate& add_interface(interface<Interface>* pi)
{
m[pi->id()] = std::unique_ptr<property>(pi);
static_cast<property*>(pi)->pagg = this;
return *this;
}
template<class Inteface>
aggregate& remove_interface()
{ m.erase[property::id_of<Inteface>()]; return *this; }
void clear() { m.clear(); }
bool empty() const { return m.empty(); }
explicit operator bool() const { return empty(); }
template<class Interface>
operator Interface*() const
{
auto i = m.find(property::id_of<Interface>());
if(i==m.end()) return nullptr;
return dynamic_cast<Interface*>(i->second.get());
}
template<class Interface>
friend aggregate& operator<<(aggregate& s, interface<Interface>* pi)
{ return s.add_interface(pi); }
private:
typedef std::map<unsigned, std::unique_ptr<property> > map_t;
map_t m;
};
}
/// this is a sample on how it can workout
class interface_A: public dynamic::interface<interface_A>
{
public:
virtual void methodA1() =0;
virtual void methodA2() =0;
};
class impl_A1: public interface_A
{
public:
impl_A1() { std::cout<<"creating impl_A1["<<this<<"]"<<std::endl; }
virtual ~impl_A1() { std::cout<<"deleting impl_A1["<<this<<"]"<<std::endl; }
virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_A2: public interface_A
{
public:
impl_A2() { std::cout<<"creating impl_A2["<<this<<"]"<<std::endl; }
virtual ~impl_A2() { std::cout<<"deleting impl_A2["<<this<<"]"<<std::endl; }
virtual void methodA1() { std::cout<<"interface_A["<<this<<"]::methodA1 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodA2() { std::cout<<"interface_A["<<this<<"]::methodA2 on impl_A2 in aggregate "<<get_aggregate()<<std::endl; }
};
class interface_B: public dynamic::interface<interface_B>
{
public:
virtual void methodB1() =0;
virtual void methodB2() =0;
};
class impl_B1: public interface_B
{
public:
impl_B1() { std::cout<<"creating impl_B1["<<this<<"]"<<std::endl; }
virtual ~impl_B1() { std::cout<<"deleting impl_B1["<<this<<"]"<<std::endl; }
virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B1 in aggregate "<<get_aggregate()<<std::endl; }
};
class impl_B2: public interface_B
{
public:
impl_B2() { std::cout<<"creating impl_B2["<<this<<"]"<<std::endl; }
virtual ~impl_B2() { std::cout<<"deleting impl_B2["<<this<<"]"<<std::endl; }
virtual void methodB1() { std::cout<<"interface_B["<<this<<"]::methodB1 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
virtual void methodB2() { std::cout<<"interface_B["<<this<<"]::methodB2 on impl_B2 in aggregate "<<get_aggregate()<<std::endl; }
};
int main()
{
dynamic::aggregate agg1;
agg1 << new impl_A1 << new impl_B1;
dynamic::aggregate agg2;
agg2 << new impl_A2 << new impl_B2;
interface_A* pa = 0;
interface_B* pb = 0;
pa = agg1; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
agg2 = std::move(agg1);
pa = agg2; if(pa) { pa->methodA1(); pa->methodA2(); }
pb = *pa; if(pb) { pb->methodB1(); pb->methodB2(); }
return 0;
}
tested with MINGW4.6 on WinXPsp3
Yes it is terrible. :D
It had been done numerous times to different extents and success levels.
QT has Qobject from which everything related to them decends.
MFC has CObject from which eveything decends as does C++.net
I don't know if there is a way to make it less bad, I guess if you avoid multiple inheritance like the plague (which is otherwise a useful language feature) and reimplement the stdlib it would be better. But really if that is what you are after you are probably using the wrong language for the task.
Java and C# are much better suited to this style of programming.
#note if I have read your question wrong just delete this answer.
Check out Dynamic C++