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.
Related
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.
Is the following code valid C++? Otherwise, is there a valid way to simultaneously interpret memory as values of different type?
#include <cstdio>
struct Base { int payload; };
struct D1 : Base { void operator()(){ printf("D1: %d\n", payload);} };
struct D2 : Base { void operator()(){ printf("D2: %d\n", payload);} };
int main()
{
D1 d1;
D2& d2 = static_cast<D2&>(static_cast<Base&>(d1));
d1();
d2();
d2.payload = 3;
d1();
d2();
}
In response to #NickoPo: My use case is basically what follows. Imagine that IntBase is not necessarily cheap to copy, that there are many complex algorithms, some of which profit from numbers being prime vs. odd, and others don't:
#include <cassert>
#include <cstdio>
bool is_odd(int value) { return 0 != value % 2; }
bool is_small_prime(int value) { return 2 == value || 3 == value || 5 == value || 7 == value; }
class IntBase
{
public:
explicit IntBase(int value) : m_value(value) {}
int value() const { return m_value; }
protected:
int m_value;
};
class OddInt : public IntBase
{
public:
explicit OddInt(int value) : IntBase(value) { assert(is_odd(m_value)); }
};
class SmallPrimeInt : public IntBase
{
public:
explicit SmallPrimeInt(int value) : IntBase(value) { assert(is_small_prime(m_value)); }
};
bool is_constrainable_to_odd_int(IntBase const& x)
{
return is_odd(x.value());
}
OddInt const& constrain_to_odd_int(IntBase const& x)
{
assert(is_odd(x.value()));
return static_cast<OddInt const&>(x);
}
bool is_constrainable_to_small_prime_int(IntBase const& x)
{
return is_small_prime(x.value());
}
SmallPrimeInt const& constrain_to_small_prime_int(IntBase const& x)
{
assert(is_small_prime(x.value()));
return static_cast<SmallPrimeInt const&>(x);
}
void algorithm(IntBase const&)
{
printf("algoritm(IntBase const&)\n");
}
void algorithm(OddInt const&)
{
printf("algoritm(OddInt const&)\n");
}
void algorithm(SmallPrimeInt const&)
{
printf("algoritm(SmallPrimeInt const&)\n");
}
void test(IntBase const& x)
{
if (is_constrainable_to_small_prime_int(x))
{
algorithm(constrain_to_small_prime_int(x));
}
else if (is_constrainable_to_odd_int(x))
{
algorithm(constrain_to_odd_int(x));
}
else
{
algorithm(x);
}
}
void test(OddInt const& x)
{
if (is_constrainable_to_small_prime_int(x))
{
algorithm(constrain_to_small_prime_int(x));
}
else
{
algorithm(constrain_to_odd_int(x));
}
}
int main()
{
IntBase x(0);
OddInt y(1);
OddInt z(7);
test(x); // algoritm(IntBase const&)
test(y); // algoritm(OddInt const&)
test(z); // algoritm(SmallPrimeInt const&)
}
Related:
Can I legally reinterpret_cast between layout-compatible standard-layout types?
Answer to Safety of casting between pointers of two identical classes?
If you're going to cast while using similar interfaces while using type as a guarantee, I'd recommend that you just wrap the inner data with your new object type and then provide access to the inner data in order to transfer it from one type to another. There's no point in doing static casting or reinterpret casting if you're not going to do it safely.
Here's an example:
http://coliru.stacked-crooked.com/a/40d5efeff22fcdcd
#include <iostream>
//Base data structure to encapsulate only data.
struct data {
data(int i) : i(i) {}
int i;
};
//Wrapper around our data structure, with interfaces to access
//the values and the data; implement your own constructor to
//gate the value
class PrimeInt {
public:
PrimeInt(const int i)
: d(i) {}
PrimeInt(const data& other)
: d(other) {}
PrimeInt(data&& other)
: d(std::move(other)) {}
PrimeInt& operator=(const PrimeInt&) = default;
PrimeInt& operator=(PrimeInt&&) = default;
int get() {return d.i;};
operator data() {return d;};
private:
data d;
};
//Wrapper around our data structure, with interfaces to access
//the values and the data; implement your own constructor to
//gate the value
class OddInt {
public:
OddInt(const int i)
: d(i) {}
OddInt(const data& other)
: d(other) {}
OddInt(data&& other)
: d(std::move(other)) {}
OddInt& operator=(const OddInt&) = default;
OddInt& operator=(OddInt&&) = default;
int get() {return d.i;};
operator data() {return d;};
private:
data d;
};
//Notice that we can now implicitly cast from one type to another.
int main() {
PrimeInt pi(10);
std::cout << pi.get() << std::endl;
OddInt oi(pi);
std::cout << oi.get() << std::endl;
return 0;
}
If your objects are not cheap to copy, you are probably passing pointers or references everywhere. You can wrap pointers to your common base in different class types and pass them by value. That is, instead of this (pseudocode)
class B
class D1 : B { ... }
class D2 : B { ... }
D1* d1; D2* d2;
you have
class Bimpl
class B { Bimpl* bimpl; }
class D1 : B { ... }
class D2 : B { ... }
D1 d1; D2 d2;
Here you never do any built-in cast. If you want to convert D1 to D2, you write your own conversion function.
I have written a small piece of code where I am able to call setter and getter functions packed within a functoid using mem_fun templates.
I now would like to use this approach on top of a class hierarchy where every class might have getter and setter which can be registered as pair within a vector or array to be able to call the getter and setter if needed. GUIObject and GUICompositeObject are example classes out of the described class hierarchy.
The bound_mem_fun_t for the objects have unfortunately different types and thats the reason I don't know how to integrate them into an array/vector of pointers to the functors.
In c++11 I would use std::function. Is there a way to emulate this in c++98?
Because our compiler support only c++98 I cannot use the new features of c++11 or c++14. Also boost is not allowed.
#include <functional>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
template<typename T>
struct bound_mem_fun_t
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
int operator()() { return m_GetFunc(obj); } ;
void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
bound_mem_fun_t<GUIObject> GUIObjectFunc(std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject);
GUIObjectFunc(17);
int ii = GUIObjectFunc();
bound_mem_fun_t<GUICompositeObject> GUICompObjectFunc(std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj);
GUICompObjectFunc(17);
int iChilds = GUICompObjectFunc();
return 0;
}
Here is the complete solution after #filmors answer:
#include <functional>
#include <vector>
#include <iostream>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
struct bound_mem_fun_base
{
virtual int operator()() =0;
virtual void operator()(int) =0;
};
template<typename T>
struct bound_mem_fun_t : public bound_mem_fun_base
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
virtual int operator()() { return m_GetFunc(obj); } ;
virtual void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
template<typename T> bound_mem_fun_t<T>* make_setter(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o)
{
return new bound_mem_fun_t<T> (GetFunc, SetFunc, o);
}
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
std::vector<bound_mem_fun_base*> kBoundVector;
kBoundVector.push_back(new bound_mem_fun_t<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(new bound_mem_fun_t<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
kBoundVector.push_back(make_setter<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(make_setter<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
for (int i = 0; i < 4 ; i++)
{
(*kBoundVector[i])(i*10);
int res = (*kBoundVector[i])();
std::cout << "Getter result " << res << "\n";
}
return 0;
}
Unfortunately the make_setter function does not really shorten the creation of the functor. Any ideas will be welcome.
Just give your bound_mem_fun_t<T> a common base class and use dynamic dispatch to solve your problem:
struct bound_mem_fun_base {
virtual int operator()() = 0;
virtual void operator()(int) = 0;
};
template <typename T>
struct bound_mem_fun_t : bound_mem_fun_t ...
Then you can keep pointers to bound_mem_fun_base in your vector and call the elements as (*v[0])().
Also, TR1 does contain std::tr1::function, is that available?
First a remark on std::function from c++11: That will not solve your problem, because you need an already bounded function pointer. This pointer must be bound to your object. I believe what you need is an own implementation to std::bind.
I started only a very! small Binder class which is hopefully a starting point for your needs. If you need to have template parameter lists in older c++ versions, take a look for loki. http://loki-lib.sourceforge.net/
As a hint I can give you a short example of what i did:
class A
{
private:
int val;
public:
A(int i): val(i) {}
void Do(int i) { std::cout << "A " << val<< " " << i << std::endl; }
};
class B
{
private:
int val;
public:
B(int i): val(i){}
void Go(int i) { std::cout << "B " << val << " " << i << std::endl; }
};
class Base
{
public:
virtual void operator()(int i)=0;
};
template <typename T>
class Binder: public Base
{
void (T::*fnct)(int);
T* obj;
public:
Binder( void(T::*_fnct)(int), T*_obj):fnct(_fnct),obj(_obj){}
void operator()(int i)
{
(obj->*fnct)(i);
}
};
int main()
{
A a(100);
B b(200);
// c++11 usage for this example
//std::function<void(int)> af= std::bind( &A::Do, &a, std::placeholders::_1);
//af(1);
// hand crafted solution
Base* actions[2];
actions[0]= new Binder<A>( &A::Do, &a);
actions[1]= new Binder<B>( &B::Go, &b);
actions[0]->operator()(55);
actions[1]->operator()(77);
}
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++
Following code does NOT work, but it expresses well what I wish to do. There is a problem with the template struct container, which I think SHOULD work because it's size is known for any template argument.
class callback {
public:
// constructs a callback to a method in the context of a given object
template<class C>
callback(C& object, void (C::*method)())
: ptr.o(object), ptr.m(method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
template<class C>
struct {
C& o;
void (C::*m)();
} ptr;
};
Is there any way to do such a thing? I mean have a non-template class callback which wraps any pointer to method?
Thanks C++ gurus!
Edit:
Please see this:
Callback in C++, template member? (2)
This is a complete working example that does what I think you're trying to do:
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()() const = 0;
};
template<class C>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, void (C::*m)()) : obj(o), method(m) {}
void operator()() const { (&obj->*method)(); }
private:
C& obj;
void (C::*method)();
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C>
void set(C& o, void (C::*m)()) { spec.reset(new CallbackSpec<C>(o, m)); }
private:
std::auto_ptr<CallbackSpecBase> spec;
};
// TEST CODE
class Test
{
public:
void foo() { std::cout << "Working" << std::endl; }
void bar() { std::cout << "Like a charm" << std::endl; }
};
int main()
{
Test t;
Callback c;
c.set(t, &Test::foo);
c();
c.set(t, &Test::bar);
c();
}
I recently implemented this:
#define UNKOWN_ITEM 0xFFFFFFFF
template <typename TArg>
class DelegateI
{
public:
virtual void operator()(TArg& a)=0;
virtual bool equals(DelegateI<TArg>* d)=0;
};
template <class TArg>
class Event
{
public:
Event()
{
}
~Event()
{
for (size_t x=0; x<m_vDelegates.size(); x++)
delete m_vDelegates[x];
}
void operator()(TArg& a)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
m_vDelegates[x]->operator()(a);
}
}
void operator+=(DelegateI<TArg>* d)
{
if (findInfo(d) != UNKOWN_ITEM)
{
delete d;
return;
}
m_vDelegates.push_back(d);
}
void operator-=(DelegateI<TArg>* d)
{
uint32 index = findInfo(d);
delete d;
if (index == UNKOWN_ITEM)
return;
m_vDelegates.erase(m_vDelegates.begin()+index);
}
protected:
int findInfo(DelegateI<TArg>* d)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
if (m_vDelegates[x]->equals(d))
return (int)x;
}
return UNKOWN_ITEM;
}
private:
std::vector<DelegateI<TArg>*> m_vDelegates;
};
template <class TObj, typename TArg>
class ObjDelegate : public DelegateI<TArg>
{
public:
typedef void (TObj::*TFunct)(TArg&);
ObjDelegate(TObj* t, TFunct f)
{
m_pObj = t;
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
ObjDelegate<TObj,TArg> *d = dynamic_cast<ObjDelegate<TObj,TArg>*>(di);
if (!d)
return false;
return ((m_pObj == d->m_pObj) && (m_pFunct == d->m_pFunct));
}
virtual void operator()(TArg& a)
{
if (m_pObj && m_pFunct)
{
(*m_pObj.*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
TObj* m_pObj; // pointer to object
};
template <typename TArg>
class FunctDelegate : public DelegateI<TArg>
{
public:
typedef void (*TFunct)(TArg&);
FunctDelegate(TFunct f)
{
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
FunctDelegate<TArg> *d = dynamic_cast<FunctDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pFunct == d->m_pFunct);
}
virtual void operator()(TArg& a)
{
if (m_pFunct)
{
(*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
};
template <typename TArg>
class ProxieDelegate : public DelegateI<TArg>
{
public:
ProxieDelegate(Event<TArg>* e)
{
m_pEvent = e;
}
virtual bool equals(DelegateI<TArg>* di)
{
ProxieDelegate<TArg> *d = dynamic_cast<ProxieDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pEvent == d->m_pEvent);
}
virtual void operator()(TArg& a)
{
if (m_pEvent)
{
(*m_pEvent)(a);
}
}
Event<TArg>* m_pEvent; // pointer to member function
};
template <class TObj, class TArg>
DelegateI<TArg>* delegate(TObj* pObj, void (TObj::*NotifyMethod)(TArg&))
{
return new ObjDelegate<TObj, TArg>(pObj, NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(void (*NotifyMethod)(TArg&))
{
return new FunctDelegate<TArg>(NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(Event<TArg>* e)
{
return new ProxieDelegate<TArg>(e);
}
use it like so:
define:
Event<SomeClass> someEvent;
enlist callbacks:
someEvent += delegate(&someFunction);
someEvent += delegate(classPtr, &class::classFunction);
someEvent += delegate(&someOtherEvent);
trigger:
someEvent(someClassObj);
You can also make your own delegates and overide what they do. I made a couple of others with one being able to make sure the event triggers the function in the gui thread instead of the thread it was called.
You need to use polymorphism. Use an abstract base class with a virtual invocation method (operator() if you please), with a templated descendant that implements the virtual method using the correct type signature.
The way you have it now, the data holding the type is templated, but the code meant to invoke the method and pass the object isn't. That won't work; the template type parameters need to flow through both construction and invocation.
#Barry Kelly
#include <iostream>
class callback {
public:
virtual void operator()() {};
};
template<class C>
class callback_specialization : public callback {
public:
callback_specialization(C& object, void (C::*method)())
: o(object), m(method) {}
void operator()() {
(&o ->* m) ();
}
private:
C& o;
void (C::*m)();
};
class X {
public:
void y() { std::cout << "ok\n"; }
};
int main() {
X x;
callback c(callback_specialization<X>(x, &X::y));
c();
return 0;
}
I tried this, but it does not work (print "ok")... why?
Edit:
As Neil Butterworth mentioned, polymorphism works through pointers and references,
X x;
callback& c = callback_specialization<X>(x, &X::y);
c();
Edit:
With this code, I get an error:
invalid initialization of non-const reference of type ‘callback&’
from a temporary of type ‘callback_specialization<X>’
Now, I don't understand that error, but if I replace callback& c with const callback& c and virtual void operator()() with virtual void operator()() const, it works.
You didn't say what errors you found, but I found that this worked:
template<typename C>
class callback {
public:
// constructs a callback to a method in the context of a given object
callback(C& object, void (C::*method)())
: ptr(object,method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
// template<class C>
struct Ptr{
Ptr(C& object, void (C::*method)()): o(object), m(method) {}
C& o;
void (C::*m)();
} ptr;
};
Note that Ptr needs a constructor as it has a reference member.
You could do without struct Ptr and have the raw members.
Tested with VS2008 express.
Improving the OP's answer:
int main() {
X x;
callback_specialization<X> c(x, &X::y);
callback& ref(c);
c();
return 0;
}
This prints "ok".
Tested on VS2008 express.
Please see this
Callback in C++, template member? (2)