Why does my class polymorphism fail (C++) - c++

I want to return a struct which uses a number and one object deriving from one of 3 subclasses that tell the method where to add the number. My thought process is that using runtime polymorphism, I can overload the method and have the sum of different sub classes in 3 variables. However this doesn't seem to happen because the object doesn't get casted down to it's child class. Bear in mind, that the program doesn't know beforehand which subclass will be the struct, so manual casting is not possible.
The class with the subclasses (s.h):
#pragma once
class Sugar{};
class Nincs : public Sugar
{
private:
static Nincs* ins;
Nincs(){};
public:
static Nincs* instance();
};
class Alfa : public Sugar
{
private:
static Alfa* ins;
Alfa(){};
public:
static Alfa* instance();
};
class Delta : public Sugar
{
private:
static Delta* ins;
Delta(){};
public:
static Delta* instance();
};
The class with the subclasses (s.cpp):
#include "s.h"
Nincs* Nincs::ins = nullptr;
Alfa* Alfa::ins = nullptr;
Delta* Delta::ins = nullptr;
Nincs* Nincs::instance()
{
if (ins == nullptr)
{
ins = new Nincs();
}
return ins;
};
Alfa* Alfa::instance()
{
if (ins == nullptr)
{
ins = new Alfa();
}
return ins;
}
Delta* Delta::instance()
{
if (ins == nullptr)
{
ins = new Delta();
}
return ins;
}
The classes that return the struct (this is only n.h for now, I plan to separate it into .h and .cpp once this issue is resolved):
#pragma once
#include "s.h"
struct Sugarzas
{
Sugar* fajta;
int mennyiseg;
};
class Noveny
{
protected:
std::string nev;
int tapanyag;
bool el_e;
public:
Noveny(std::string v1, int v2, bool v3): nev(v1), tapanyag(v2), el_e(v3){}
virtual Sugarzas ker(){};
};
class Puffancs : public Noveny
{
public:
Puffancs(std::string v1, int v2, bool v3): Noveny(v1,v2,v3){};
Sugarzas ker() override
{
Sugarzas s;
s.fajta = Alfa::instance();
s.mennyiseg = 10;
return s;
}
};
class Deltafa : public Noveny
{
public:
Deltafa(std::string v1, int v2, bool v3): Noveny(v1,v2,v3){};
Sugarzas ker() override
{
Sugarzas s;
s.fajta = Delta::instance();
if (tapanyag < 5)
{
s.mennyiseg = 4;
}
else if (tapanyag >=5 && tapanyag <=10)
{
s.mennyiseg = 1;
}
else
{
s.mennyiseg = 0;
}
return s;
}
};
class Parabokor : public Noveny
{
public:
Parabokor(std::string v1, int v2, bool v3): Noveny(v1,v2,v3){};
Sugarzas ker() override{}
};
main file with the functions:
#include <iostream>
#include "s.h"
#include "n.h"
using namespace std;
int sumNincs, sumAlfa, sumDelta;
void addTo(Nincs* s, int x)
{
sumNincs += x;
}
void addTo(Alfa* s, int x)
{
sumAlfa += x;
}
void addTo(Delta* s, int x)
{
sumDelta += x;
}
int main()
{
Puffancs* n = new Puffancs("bob",5,true);
sumNincs = 0;
sumAlfa = 0;
sumDelta = 0;
Sugarzas s = n->ker();
addTo(s.fajta,s.mennyiseg); //s.fajta comes out as Sugar* and does not get casted to the subclasses
return 0;
}

It looks like there's some confusion between function overloading and function overriding. Virtual functions can be overridden, where a member function defined in a base class can be overridden by a member function with the same signature* in a derived class, and then calls to the base class method will be dispatched based on the actual runtime most derived class of the object the methods are being called on.
*Except possibly having a covariant return type.
However, your addTo functions are not a case of overriding. They are a case of overloading, where you have functions with the same name but different signatures. Overload resolution must be resolved at compile time. The static type of s.fajta is Sugar*, even though the actual pointed-to object is an Alfa.
You'd need your Sugar class to have virtual methods if you want to be able to have behavior that depends on the concrete type of *s.fajta. Since I'm not clear on what exactly is supposed to be happening here, I'm not sure how to restructure your program to use this behavior.

Related

What is an easy way to assign member variables of base class templates

I have a class called interface that takes a file provided by user input and then depending on that file type it will initialize a member variable of type BaseDefinitions that is used to map out the specific bytes of the file.
Base
template<class T, class U>
class BaseDefinition
{
public:
T getHeaderBlock() { T new_header_block = {}; return new_header_block; };
U getDataBlock() { U new_data_block = {}; return new_data_block; };
virtual bool validateBytes(T& definition) = 0;
virtual float getDataPoint(U& data) = 0;
};
Derived
struct FileAHeaderBlock {
...
};
struct FileADataBlock {
...
};
class FileADefinition : public BaseDefinition<FileAHeaderBlock, FileADataBlock >
{
public:
bool validateBytes(FileAHeaderBlock& definition) override;
float getDataPoint(FileADataBlock & data) override;
}
Interface header file
class FileInterface
{
public:
FileInterface();
~FileInterface();
void loadDefinition(std::string &file_type);
private:
void extract_header();
BaseDefinition* definition_; //Here is the member variable I am trying to set
std::vector<int> values_;
};
Interface.cpp
void FileInterface::load_defintion(const std::string& filepath)
{
//Psuedo code
if (file_type == std::string(".fileA"))
definition_ = FileADefinition;
else if (file_type == std::string(".fileB"))
definition = FileBDefinition;
}
void FileInterface::extract_header()
{
auto header_buffer = definition_.getHeaderBlock();
//read bits into header buffer
if (!file_.read((char*)(&header_buffer), sizeof(header_buffer)))
{
throw std::runtime_error("File could not be read: ");
}
if (!definition_.validateBytes(header_buffer))
{
std::cout << "got: " << std::string(std::begin(header_buffer.MAGIC), std::end(header_buffer.MAGIC)) << std::endl;
}
values_ = header_buffer.DATA;
}
When I try to build this I get a compiler error from Visual studio saying that the argument list for class template BaseDefinition is missing.
I thought I could set the member variable to a base class then cast to a derived class when I know what file the user wants.
The classes FileADefinition and FileBDefinition both have the same functions just different implementation so I would really like to take advantage of the Object Oriented nature. It seems the structure I use to initialize them is the sticking point. What am I missing that could be done here?
Something along these lines, perhaps. This should be functionally equivalent to your current example.
class BaseDefinition {
public:
virtual std::vector<int> extract_header(std::istream& input) = 0;
};
template <typename T, typename U>
class BaseDefinitionImpl : public BaseDefinition {
protected:
virtual bool validateBytes(T& definition) = 0;
public:
std::vector<int> extract_header(std::istream& input) override {
T header_buffer;
if (!file_.read((char*)(&header_buffer), sizeof(header_buffer)))
{
throw std::runtime_error("File could not be read: ");
}
if (!validateBytes(header_buffer)) {
std::cout << "Bad things happened";
}
return header_buffer.DATA;
}
};
class FileADefinition : public BaseDefinitionImpl<FileAHeaderBlock, FileADataBlock >
{
public:
bool validateBytes(FileAHeaderBlock& definition) override;
}
class FileInterface {
public:
void loadDefinition(std::string &file_type) {
if (file_type == std::string(".fileA"))
definition_ = std::make_unique<FileADefinition>();
}
private:
void extract_header() {
values_ = definition_->extract_header(file_);
}
std::unique_ptr<BaseDefinition> definition_;
std::vector<int> values_;
};

Can't call class function from a template function class inside a template class

I am trying to create a pattern where an abstract class has several methods where all get the same member. The derived implementation is on a specific member type and the pattern should redundant the need to downcast the types.
The following is not working:
Assume these type classes
//--------------
// Data classes
//--------------
class TypeA
{
virtual int a() = 0;
};
class TypeB : public TypeA
{
int a() override
{
return 5;
}
};
Pattern:
//-------------------
// Base action class.
//-------------------
class ExampleBase
{
public:
virtual bool f1(TypeA& val) = 0;
virtual bool f2(TypeA& val) = 0;
};
//----------------------------------
// Base specific Typed action class.
//----------------------------------
template<class T>
class ExampleSpecific1 : public ExampleBase
{
public:
virtual bool specificF1(T& specificVal) = 0;
virtual bool specificF2(T& specificVal) = 0;
bool f1(TypeA& val) override
{
return fRunner<bool, specificF1>(val, false);
}
bool f2(TypeA& val) override
{
return fRunner<bool, specificF2>(val, false);
}
private:
// Run the specific function with the specific type
template<class S, S (*pf)(T& val)>
S fRunner(TypeA& val, S defaultValue)
{
S ret = defaultValue;
T& specificVal = dynamic_cast<T&>(val);
if (&specificVal != nullptr) {
ret = pf(specificVal);
}
return ret;
}
};
The implementation
//----------------------
// Class Implementation.
//----------------------
class ExampleImpl : public ExampleSpecific1<TypeB>
{
public:
bool specificF1(TypeB& specificVal) override
{
// Do something
}
bool specificF2(TypeB& specificVal) override
{
// Do something
}
};
Usage:
//-----------
// Class Use.
//-----------
void main()
{
ExampleImpl impl;
TypeB myVal;
TypeA& myBaseVal = myVal;
impl.f1(myBaseVal);
impl.f2(myBaseVal);
}
I get the following compilation error:
error C2672: 'ExampleSpecific1<TypeB>::fRunner': no matching overloaded function found
note: while compiling class template member function 'bool ExampleSpecific1<TypeB>::f2(TypeA &)'
note: see reference to function template instantiation 'bool ExampleSpecific1<TypeB>::f2(TypeA &)' being compiled
note: see reference to class template instantiation 'ExampleSpecific1<TypeB>' being compiled
error C2975: 'pf': invalid template argument for 'ExampleSpecific1<TypeB>::fRunner', expected compile-time constant expression
note: see declaration of 'pf'
A function template that does work (when the function is not inside a class):
Based on the previous example:
template<class T, bool (*pf1)(T& Val), bool (*pf2)(T& Val)>
class ExampleSpecific2 : public ExampleBase
{
public:
bool f1(TypeA& val) override
{
bool ret = false;
T& specificVal = dynamic_cast<T&>(val);
if (&specificVal != nullptr) {
ret = pf1(specificVal);
}
return ret;
}
bool f2(TypeA& val) override
{
bool ret = false;
T& specificVal = dynamic_cast< T&>(val);
if (&specificVal != nullptr) {
ret = pf2(specificVal);
}
return ret;
}
};
External functions:
bool extF1(TypeB& val)
{
// Do something.
}
bool extF2(TypeB& val)
{
// Do something.
}
Useage:
//-----------
// Class Use.
//-----------
void main()
{
TypeB myVal;
TypeA& myBaseVal = myVal;
ExampleSpecific2<TypeB, extF1, extF2> impl2;
impl2.f1(myBaseVal);
impl2.f2(myBaseVal);
}
In the example that does not work, I can implement the down cast in each of the implementation and then it works, but it is ugly and is not generic. In the working example I want the function to be in the internal implementation of the class and not external to it, this is important in more complicated scenarios, where the base class is calling several of the derived methods.
BTW I don't like this post Title, if you have a better suggestion that I like, this will be great.
Note :
main should return an int, not void
if (&specificVal != nullptr) will be always true, reference cannot be null.
I am not sur why you got this error message, with gcc I got :
no matching member function for call to 'fRunner'
Because pf type was bool (ExampleSpecific1<TypeB>::*)(TypeB &) which didn't match with S (*pf)(T& val). The first one need an class object.
So I just use the C++17 auto :
template<class S, auto pf>
S fRunner(TypeA& val, S defaultValue){...}
But you can use the full type if you want.
Next We need to call the member function. I don't like (nor remember) the member function call syntaxe, so I just use std::invoke of C++17. (see : https://en.cppreference.com/w/cpp/utility/functional/invoke)
Live : https://wandbox.org/permlink/rEqgLSwSjEfqRK2o
#include <iostream>
#include <vector>
//--------------
// Data classes
//--------------
class TypeA
{
virtual int a() = 0;
};
class TypeB : public TypeA
{
int a() override
{
return 5;
}
};
//-------------------
// Base action class.
//-------------------
class ExampleBase
{
public:
virtual bool f1(TypeA& val) = 0;
virtual bool f2(TypeA& val) = 0;
};
//----------------------------------
// Base specific Typed action class.
//----------------------------------
template<class T>
class ExampleSpecific1 : public ExampleBase
{
private:
// Run the specific function with the specific type
template<class S, auto pf>
S fRunner(TypeA& val, S defaultValue)
{
S ret = defaultValue;
T& specificVal = dynamic_cast<T&>(val);
ret = std::invoke(pf, *this, specificVal);
return ret;
}
public:
virtual bool specificF1(T& specificVal) = 0;
virtual bool specificF2(T& specificVal) = 0;
bool f1(TypeA& val) override
{
return this->fRunner<bool, &ExampleSpecific1<T>::specificF1>(val, false);
}
bool f2(TypeA& val) override
{
return this->fRunner<bool, &ExampleSpecific1<T>::specificF2>(val, false);
}
};
// Class Implementation.
//----------------------
class ExampleImpl : public ExampleSpecific1<TypeB>
{
public:
bool specificF1(TypeB& ) override
{
std::cout << "specificF1" << std::endl;
return true;
}
bool specificF2(TypeB& ) override
{
std::cout << "specificF2" << std::endl;
return true;
}
};
//-----------
// Class Use.
//-----------
int main()
{
ExampleImpl impl;
TypeB myVal;
TypeA& myBaseVal = myVal;
impl.f1(myBaseVal);
impl.f2(myBaseVal);
}
Pre C++17 : https://wandbox.org/permlink/HSGMy4zb4TgusESf
template<class S, S (ExampleSpecific1<T>::*pf)(T &)> // full type since auto is C++ 17
S fRunner(TypeA& val, S defaultValue)
{
S ret = defaultValue;
T& specificVal = dynamic_cast<T&>(val);
ret = (this->*pf)(specificVal); // Ugly pre 17
return ret;
}

Determine Class Implementation Dynamically via Constructor

I want to create a class which behaves a certain way - e.g. spits out certain values from a function double getValue(const int& x) const - based on a "type" that was passed into its constructor. Right now I have two methods:
Store the passed-in "type" and then evaluate a switch statement in getValue each time it is called in order to decide which implementation to use.
Use a switch statement on the passed-in "type" (in the constructor) to create an internal object that represents the desired implementation. So no switch required anymore in getValue itself.
Method 1 "appears" inefficient as switch is called every time I call getValue. Method 2 seems somewhat clunky as I need to utilise <memory> and it also makes copying/assigning my class non-trivial.
Are there any other cleaner methods to tackle a problem like this?
Code Example:
#include <memory>
enum class ImplType { Simple1, Simple2 /* more cases */ };
class MyClass1
{
private:
const ImplType implType;
public:
MyClass1(const ImplType& implType) : implType(implType) { }
double getValue(const int& x) const
{
switch (implType)
{
case ImplType::Simple1: return 1; /* some implemention */
case ImplType::Simple2: return 2; /* some implemention */
}
}
};
class MyClass2
{
private:
struct Impl { virtual double getValue(const int& x) const = 0; };
struct ImplSimple1 : Impl { double getValue(const int& x) const override { return 1; /* some implemention */ } };
struct ImplSimple2 : Impl { double getValue(const int& x) const override { return 2; /* some implemention */ } };
const std::unique_ptr<Impl> impl;
public:
MyClass2(const ImplType& implType) : impl(std::move(createImplPtr(implType))) { }
static std::unique_ptr<Impl> createImplPtr(const ImplType& implType)
{
switch (implType)
{
case ImplType::Simple1: return std::make_unique<ImplSimple1>();
case ImplType::Simple2: return std::make_unique<ImplSimple2>();
}
}
double getValue(const int& x) const { return impl->getValue(x); }
};
int main()
{
MyClass1 my1(ImplType::Simple1);
MyClass2 my2(ImplType::Simple1);
return 0;
}
Your code is basically mimicing a virtual method (sloppy speaking: same interface but implementation is chosen at runtime), hence your code can be much cleaner if you actually do use a virtual method:
#include <memory>
struct base {
virtual double getValue(const int& x) const = 0;
};
struct impl1 : base {
double getValue(const int& x) { return 1.0; }
};
struct impl2 : base {
double getValue(const int& x) { return 2.0; }
};
// ... maybe more...
enum select { impl1s, impl2s };
base* make_impl( select s) {
if (s == impl1s) return new impl1();
if (s == impl2s) return new impl2();
}
int main() {
std::shared_ptr<base> x{ make_impl(impl1) };
}
Not sure if this is what you are looking for. By the way, using <memory> should not make you feel "clunky", but instead you should feel proud that we have such awesome tools in c++ ;).
EDIT: If you dont want the user to work with (smart-)pointers then wrap the above in just another class:
struct foo {
shared_ptr<base> impl;
foo( select s) : impl( make_impl(s) ) {}
double getValue(const int& x) { return impl.getValue(x); }
};
now a user can do
int main() {
auto f1 { impl1s };
auto f2 { impl2s };
f1.getValue(1);
f2.getValue(2);
}
If you have a closed set of types you can choose from, you want std::variant:
using MyClass = std::variant<MyClass1, MyClass2, MyClass3, /* ... */>;
It doesn't use dynamic allocation - it's basically a type-safe modern alternative to union.
More object-oriented approach:
class Interface
{
public:
virtual int getValue() = 0;
};
class GetValueImplementation1 : public Interface
{
public:
int getValue() {return 1;}
};
class GetValueImplementation2 : public Interface
{
public:
int getValue() {return 2;}
};
class GeneralClass
{
public:
GeneralClass(Interface *interface) : interface(interface) {}
~GeneralClass()
{
if (interface)
delete interface;
}
int getValue() { return interface->getValue(); }
private:
Interface *interface;
};
So, in this case you can use it without any pointers:
int main()
{
GeneralClass obj1(new GetValueImplementation1());
GeneralClass obj2(new GetValueImplementation2());
cout << obj1.getValue() << " " << obj2.getValue();
return 0;
}
The output will be:
1 2
But in the case you should be careful with null pointers or use smart ones inside GeneralClass.

How to use an integer id to identify a class in a class hierarchy automatically?

For example, I have a base class A and its sub-classes B, C and so on. B and C can also has its sub-classes. The structure is a tree with root A. And each class in the tree is assigned a different integer to identify itself. There is no restriction on the integer id's values and orders. Just make sure they are different for different classes.
My question is how to do it smartly (or automatically) by using like template techniques since manual assignment is error-prone. Any way to get the id is fine, like
class A
{
public:
static const id = ...;
};
or
template<class A>
struct Id
{
enum { value = ... };
};
Easiest way is just a function
int nextId() {
static int rval = 1;
return rval++;
}
class A { public: static const id = nextId(); };
class B { public: static const id = nextId(); };
class C { public: static const id = nextId(); };
That will work so long as you do not need to use the IDs in dynamic initialization at the start of the program.
Edit: if that is not sufficient, the next step up is to do the same thing with static variables in a template. This works across compilation units, but is still dynamic initialization time.
template <typename DummyT = void>
struct CommonCounter
{
public:
static int nextId() {
static int rval = 1;
return rval ++;
}
};
template <typename T>
struct IdFor
{
static int value()
{
static int rval = CommonCounter<>::nextId();
return rval;
}
};
class A { public: static const id = IdFor<A>::get(); };
You could do something like this. This should give the same order on the same compiler. You could also modify how you key things to get a known order and detect problems at initialisation time. Simple implementation, not tested.
#include <typeinfo>
class A {
public:
virtual ~A();
static void register_type(std::type_info const& t);
int id() const;
};
template<class T>
struct DoInitA
{
DoInitA() { A::register_type(typeid(T)); }
};
class B : public A
{
static DoInitA<B> s_a_init;
public:
~B() { }
};
//
// Implementation file.
//
#include <vector>
#include <functional>
namespace {
struct TypeinfoLess {
typedef std::reference_wrapper<const std::type_info> value_type;
bool operator()(value_type const& lhs, value_type const& rhs) const {
return lhs.get().before(rhs.get());
}
};
}
typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;
static TypeVector s_types;
static bool s_init_complete = false;
A::~A() { }
void A::register_type(std::type_info const& t)
{
static int s_counter = 0;
if (s_init_complete)
throw std::runtime_error("Late initialisation");
s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}
int A::id() const
{
if (!s_init_complete) {
sort(s_types.begin(), s_types.end(), TypeinfoLess());
s_init_complete = true;
}
for (size_t i = 0; i < s_types.size(); ++i)
if (s_types[i].get() == typeid(*this)) return i;
throw std::runtime_error("Uninitialised type");
}

Dynamic Object in C++?

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++