I have a code:
#include "stdafx.h"
#include "memory"
#include <gtest\gtest.h>
class Money
{
public:
explicit Money(int value) :value(value) {} ;
Money(Money&& m) :value(m.returnValue()) {};
Money(const Money &m) = default;
Money operator-(const Money &m) ;
Money &operator=(Money &&m) { return Money(m.returnValue()); };
Money &operator=(const Money &m)=default;
int returnValue() const { return value; };
~Money() = default;
private:
int value;
};
Money Money::operator-(const Money &m)
{
return Money(value - m.returnValue());
}
class Bank {
public:
Bank(Money m) :propertiesBank(std::make_unique<PropertiesBank>(std::move(m))) {};
int returnMoney() const { return propertiesBank->money->returnValue(); }
~Bank() = default;
private:
struct PropertiesBank;
std::unique_ptr<PropertiesBank> propertiesBank;
};
struct Bank::PropertiesBank
{
std::shared_ptr<Money> money;
PropertiesBank(Money&& m) :money(std::make_shared<Money>(m)) {};
};
int main()
{
Money k(1000);
Bank bank(k);
return 0;
}
I want display(returnMoney()) money in the Bank, but I can't. I could make class with struct Impl and unique_ptr for training.
I know, that unique can't copy.
How can I make this programm?
Are the rest of my code is well?
Error
Error C2027 use of undefined type 'Bank::PropertiesBank' Error
C2039 'returnValue': is not a member of 'std::unique_ptr>'
The only issue I can see is that the definition of Bank::returnMoney tries to access Bank::PropertiesBank when it has only been forward-declared, not defined. Moving PropertiesBank to be defined incline within Bank fixes this.
However as Mooing Duck points out in the comments, if your intention is to implement the pImpl idiom, then both Bank::PropertiesBank and Bank::returnMoney should be defined in a .cpp file, rather than within the class definition.
#include <memory>
class Money
{
public:
explicit Money(int value) :value(value) {} ;
Money(Money&& m) :value(m.returnValue()) {};
Money(const Money &m) = default;
Money operator-(const Money &m) ;
Money operator==(Money &&m) { return Money(m.returnValue()); };
int returnValue() const { return value; };
~Money() = default;
private:
int value;
};
Money Money::operator-(const Money &m)
{
return Money(value - m.returnValue());
}
class Bank {
public:
Bank(Money m) :propertiesBank(std::make_unique<PropertiesBank>(std::move(m))) {};
int returnMoney() const { return propertiesBank->money->returnValue(); }
~Bank() = default;
private:
struct PropertiesBank
{
std::shared_ptr<Money> money;
int returnMoney() const { return money->returnValue(); }
PropertiesBank(Money&& m) :money(std::make_shared<Money>(m)) {};
};
std::unique_ptr<PropertiesBank> propertiesBank;
};
#include <iostream>
int main()
{
Money m(10);
Bank b(m);
std::cout << b.returnMoney();
return 0;
}
Its not a problem with std::unique_ptr, its the fact that you tried accessing a member of an object whose type is PropertiesBank when the compiler hasn't seen its full definition. You should move the definition of the member function outside the class and at the point where the compiler has seen the full definition of PropertiesBank:
See the comment in this snippet below:
class Bank {
public:
Bank(Money m) :propertiesBank(std::make_unique<PropertiesBank>(std::move(m))) {};
int returnMoney() const;{ return propertiesBank->money->returnValue(); }
// .......The compiler doesn't know that `money`^^^^^^ belongs to `PropertiesBank`
~Bank() = default;
private:
struct PropertiesBank;
std::unique_ptr<PropertiesBank> propertiesBank;
};
struct Bank::PropertiesBank
{
std::shared_ptr<Money> money;
PropertiesBank(Money&& m) :money(std::make_shared<Money>(m)) {};
};
You should move the function's definition to after where the compiler has seen the definition of the type of propertiesBank:
class Bank {
public:
Bank(Money m) :propertiesBank(std::make_unique<PropertiesBank>(std::move(m))) {};
int returnMoney() const; //member function declaration
~Bank() = default;
private:
struct PropertiesBank;
std::unique_ptr<PropertiesBank> propertiesBank;
};
struct Bank::PropertiesBank
{
std::shared_ptr<Money> money;
PropertiesBank(Money&& m) :money(std::make_shared<Money>(m)) {};
};
//Member function's definition
int Bank::returnMoney() const { return propertiesBank->money->returnValue(); }
Related
The addBudget function in AuxiliaryOffice class is a friend function of the budget class. But the compiler is giving me error, that it cannot access the private members of the Budget class.
class Budget;
class AuxiliaryOffice
{
private:
double auxBudget;
public:
AuxiliaryOffice()
{
auxBudget = 0;
}
double getDivisionBudget()
{
return auxBudget;
}
void addBudget(double a, Budget &ref)
{
ref.corpBudget += a;
auxBudget += a;
}
};
class Budget
{
private:
static double corpBudget;
double divisionBudget;
friend void AuxiliaryOffice::addBudget(double, Budget&);
public:
Budget()
{
divisionBudget = 0;
}
void addBudget(double a)
{
corpBudget += a;
divisionBudget += a;
}
double getDivisionBudget() const
{
return divisionBudget;
}
double getCorpBudget() const
{
return corpBudget;
}
};
double Budget::corpBudget = 0;
The error you get is stopping your code from compile before friendship is even an issue.
You declared Budget as an incomplete type:
class Budget;
And then wrote code that calls functions on it, before the class is defined. That is not allowed. You have to declare functions that use it, but NOT define it until after the class is defined.
That's why (one of the reasons why) we put class declarations in headers, and implementations in .cpp files. It also reduces coupling between files, and can help with build speeds.
Here's a compacted version of your code that compiles, with most of the unessential lines removed (as you should aim to do in future questions):
class Budget;
class AuxiliaryOffice {
double auxBudget = 0;
public:
void addBudget(double a, Budget &ref);
};
class Budget {
// Unrelated, but useful to know:
// inline statics can be initialized in the class like this, no
// definition necessary in the .cpp file.
inline static double corpBudget = 0;
friend void AuxiliaryOffice::addBudget(double, Budget&);
};
// if in .cpp, remove "inline", if in header, keep it
inline void AuxiliaryOffice::addBudget(double a, Budget &ref) {
ref.corpBudget += a;
}
see it live: https://godbolt.org/z/JYDZMz
The problem is not about friendship, is about the order of definition. At the point you've defined AuxiliaryOffice::addBudget the definition of Budget is incomplete, hence the member corpBudget isn't defined yet.
Change it to:
class Budget;
class AuxiliaryOffice
{
private:
double auxBudget;
public:
AuxiliaryOffice()
{
auxBudget = 0;
}
double getDivisionBudget()
{
return auxBudget;
}
void addBudget(double a, Budget &ref);
};
class Budget
{
private:
static double corpBudget;
double divisionBudget;
friend void AuxiliaryOffice::addBudget(double, Budget&);
public:
Budget()
{
divisionBudget = 0;
}
void addBudget(double a)
{
corpBudget += a;
divisionBudget += a;
}
double getDivisionBudget() const
{
return divisionBudget;
}
double getCorpBudget() const
{
return corpBudget;
}
};
double Budget::corpBudget = 0;
inline void AuxiliaryOffice::addBudget(double a, Budget &ref)
{
ref.corpBudget += a;
auxBudget += a;
}
That will work.
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.
I am trying to write a C++ program which wraps numeric values, I am doing this by writing a super class which will handle two simple functions, and an operator overloading function. This is the code I have so far:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
template <class T>
class Number {
protected:
T number;
public:
Number(T num) {
number = num;
}
string mytype() {
return typeid(number).name();
}
string what_am_i() {
ostringstream oss;
oss << "I am " << Number<T>::mytype() << " and my value is " << number;
return oss.str();
}
Number operator+ (Number an) {
Number brandNew = NULL;
brandNew.number = number + an.number;
return brandNew;
}
};
class MyInt : public Number<int> {
public:
MyInt() : Number<int>(0) {};
MyInt(int num) : Number<int>(num) {}
MyInt(const Number<int> &x) : Number<int>(x) {}
};
class MyFloat : public Number<float> {
public:
MyFloat() : Number<float>(0){};
MyFloat(float num) : Number(num){}
MyFloat(const Number<float> &x) : Number<float>(x) {}
};
class MyDouble : public Number<double> {
public:
MyDouble() : Number<double>(0){};
MyDouble(double num) : Number(num){}
MyDouble(const Number<double> &x) : Number<double>(x) {}
};
In the main function I would like to do something like :
void main() {
MyInt two = 2;
MyFloat flo = 5.0f;
MyDouble md3 = flo + two;
}
And wish for md3 to be 15.00000, up to now an addition of two objects from the same type works great but when I am trying to add a MyInt and MyFloat the compiler doesn't like it. Does anyone have an idea how could I implement this?
You have to add the type operator for your template class:
operator T()
{
return number;
}
This is the complate code that I tested and work:
template <class T>
class Number {
protected:
T number;
public:
Number(T num) {
number = num;
}
string mytype() {
return typeid(number).name();
}
string what_am_i() {
ostringstream oss;
oss << "I am " << Number<T>::mytype() << " and my value is " << number;
return oss.str();
}
Number operator+ (Number an) {
Number brandNew = NULL;
brandNew.number = number + an.number;
return brandNew;
}
operator T()
{
return number;
}
};
I try to explain better why it works. When you make overloading of the plus operator, you want to do something like: left_value + right_value, where right_value is the "an" argument of the plus operator.
Now to get the right value of your object "an", you have to overloading the "type operator", if you don't make overloading of this operator inside your Number class it can not be read as a right value. The following example is for the operator=(), but is valid also for operator+():
template<typename T>
class Number
{
T value;
public:
T operator=(T arg) // Assignment, your class is seen as left operand
{
value = arg;
}
operator T() // Getting, your class is seen as right operand
{
return value;
}
}
Number<int> A; // define a new class Number as int
Number<double> B; // define a new class Number as double
A = B; // is same to A.operator=( B.double() );
to assign A as left value is called the operator "operator=()" of the class Number, while to get B as right value is called the "operator T()" of the class Number
Now this is translated as:
// instance of the operator = of the class Number<int>
int operator=(int arg)
{
}
// instance of the Operator T of the class Number<double>
operator double()
{
}
this traslation emulates the follwoing semantic for A and B object:
int A;
double B;
A = B;
Ciao
Angelo
You may specify the result of a binary operation and use a freestanding operator:
#include <iostream>
#include <typeinfo>
template <class T>
class Number {
template <typename>
friend class Number;
protected:
T number;
public:
Number(const T& num)
: number(num)
{}
template <typename U>
Number(const Number<U>& num)
: number(num.number)
{}
// ...
const T& value() const { return number; }
};
typedef Number<int> MyInt;
typedef Number<float> MyFloat;
typedef Number<double> MyDouble;
template <typename A, typename B>
struct NumberResult;
template <typename X>
struct NumberResult<X, X> {
typedef X type;
};
template <> struct NumberResult<int, float> { typedef float type; };
template <> struct NumberResult<float, int> { typedef float type; };
// ...
template <typename A, typename B>
inline Number<typename NumberResult<A, B>::type>
operator + (const Number<A>& a, const Number<B>& b) {
return Number<typename NumberResult<A, B>::type>(a.value() + b.value());
}
Note: Please avoid using namespace std; in a header.
It is possible to write a wrapper that takes any type that supports a certain operation, e.g.
#include <iostream>
class Houdini
{
struct I_Houdini_Impl
{
virtual void foo_impl(int x) const = 0;
virtual ~I_Houdini_Impl() { }
};
template <typename T>
struct Houdini_Impl : I_Houdini_Impl
{
Houdini_Impl(T const & t) : m_t(t) { }
void foo_impl(int x) const { m_t.foo(x); }
T m_t;
};
public:
template <typename T>
Houdini(T const & t) : m_impl(new Houdini_Impl<T>(t)) { }
void foo(int x) const { m_impl->foo_impl(x); }
protected:
private:
std::unique_ptr<I_Houdini_Impl> m_impl;
};
class A
{
public:
void foo(int x) const { std::cout << "A::foo(" << x << ")" << std::endl; }
};
class B
{
public:
template <typename T>
char foo(T const & t) const { std::cout << "B::foo(" << t << ")" << std::endl; return 'B';}
};
void houdini()
{
A a;
B b;
Houdini ha(a);
Houdini hb(b);
ha.foo(7);
hb.foo(8);
}
I can wrap anything in the Houdini-class that supports a const-method foo that can be called wih an int, regardless if it is an ordinary member function (as in class A) or a function template (as in class B) (and lets disregard for now that Houdini should exhibit value sematics). So far so good, but what I would like to do is to write a wrapper that supports binary operations, e.g. to write a wrapper that accepts any type and you can, say, add any two wrappers as long as the wrapped objects can be added and returns the wrapped return object from the addition:
class A { };
class B { };
class C { };
C operator+(A, B) { return C(); }
class Randi
{
public:
template <typename T> Randi(T ) { }
/* magic stuff goes here */
};
void randi()
{
A a;
B b;
Randi ra(a);
Randi rb(b);
Randi rc = ra + rb;
// rc is a Randi-object that wraps an object of type C
}
If I know in advance what types I am going to store I can do it by writing visitors but that is exactly what I do not want to do. I would need to unwrap both objects, try to call operator+ on the two unwrapped objects and wrap the result again but I cannot figure out how to do that.
Consider following
class Number
{
virtual Number* sum(Number* other) = 0;
};
class Int
: public Number
{
virtual Number* sum(Number* other)
{
// hard to implement since we doesn't know the type of other
}
};
class Double
: public Number
{
virtual Number* sum(Number* other)
{
// hard to implement since we doesn't know the type of other
}
};
We can do dynamic_casts in sum implementation to handle each case separately or we can use double dispatching.
class Double;
class Int;
class Number
{
public:
virtual Number* sum(Number* other) = 0;
protected
virtual Number* sum(Int* other) = 0;
virtual Number* sum(Double* other) = 0;
};
class Int
: public Number
{
virtual Number* sum(Number* other)
{
return other->sum(this);
}
virtual Number* sum(Int* other)
{
// implement int + int
}
virtual Number* sum(Double* other)
{
// implement int + double
}
};
class Double
: public Number
{
virtual Number* sum(Number* other)
{
return other->sum(this);
}
virtual Number* sum(Int* other)
{
// implement double + int
}
virtual Number* sum(Double* other)
{
// implement double + double
}
};
In bot cases implementations should be aware about all derived classes. This means that analog of Houdini_Impl for Randi class should know about all other types that may be passed to Randi's constructor which is impossible.
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++