Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic object wrapper

Tags:

c++

I'm wondering if there's a good, generic way to write an object wrapper such that you could call all the methods defined by the class it wraps on the wrapper class itself (without having to explicitly redefine the class interface in the wrapper class). For example, two different, arbitrary classes:

class InnerExample1 {
public:
    InnerExample1(int a, bool b) {...}
    void DoSomething1(int a) {...}
    bool DoSomething2(bool b) {...}
    etc...
};

class InnerExample2 {
    InnerExample2(float a, int b) {...}
    void DoWork(int a) {...}
    bool GetResult(bool b) {...}
    etc...
};

I'd like a generically defined wrapper class such that I could do:

Wrapper<InnerExample1> inner1;
inner1.DoSomething(42);
bool result = inner1.DoSomething2(false);

and

Wrapper<InnerExample2> inner2;
inner2.DoWork(21);
bool result = inner2.GetResult(true);

With 'Wrapper' being generic enough to be able to handle wrapper either class and forward all calls made on it to its inner delegate.

I've seen code for things like a factory pattern where, with variadic args, a generic factory could instantiate any class, as well as a generalizing a binding to a single member method, but nothing that's done it for the entire class. It seems likely to me that it isn't possible...but people on SO come up with all sorts of stuff I never would have :)

EDIT: I was trying to keep the question simple by leaving out unnecessary details, but I left out too many. I need the wrapper to insert some logic around each call. Say, for example, I want this wrapper to be able to count how many times each method has been called in addition to forwarding the call to the inner object.

EDIT2: To be specific, I'm trying to write a generic wrapper to implement ActiveObject pattern. I ended up doing an 'Active' base class that handles the common bits (managing the internal thread, queuing up function calls) and writing subclasses for each internal type (with their interface mimicked).

EDIT3: @id256's answer is pretty interesting, I think I'll come back around at some point and give that method a try.

like image 657
bbaldino Avatar asked Mar 13 '15 20:03

bbaldino


People also ask

What is an object wrapper?

A Wrapper class is a class whose object wraps or contains primitive data types. When we create an object to a wrapper class, it contains a field and in this field, we can store primitive data types. In other words, we can wrap a primitive value into a wrapper class object.

What are wrappers in C++?

A wrapper is just some smallish class whose purpose is to provide a different interface than the thing it wraps. For example, it is common to take a C API and write one or more classes that "wrap" it to provide an object-oriented interface rather than a procedural one.

What is wrapper in asp net?

A Wrapper class is one that "encapsulates" a resource, or another class in order to simplify or restrict the interface between the outside world and the encapsulated object.


1 Answers

It is quite possible, you can define operator-> inside the Wrapper class template. Actually this could look like:

template <typename T>
class Wrapper {
    T* pT;
public:
// ...
    T* operator->() { return pT; }
// all the needed stuff to manage pT
};

This approach is used in, for example, STL's std::auto_ptr implementation -- take a look at http://www.cplusplus.com/reference/memory/auto_ptr/

EDIT: If you need to add some logic to calls via wrapper objects, the solution above is not acceptable. However you can try some functional features combined with templates (though the approach is rather tricky):

#include <functional>
#include <iostream>


class A {
public: 
    int inc(int x) {
        printf("A::inc %i\n", x);
        return x+1;
    }       
};      

template <typename _Function>
struct function_logged : public _Function {
    const char* log_msg;

    function_logged(_Function fun, const char* _log_msg)
    : _Function(fun), log_msg(_log_msg) { } 
};  

template <typename T, typename U, typename V, T (U::*mf)(V)>
function_logged<std::binder2nd<std::mem_fun1_t<T,U,V> > > create_function_logged(const V& arg, const char* log_msg) {
    return function_logged<std::binder2nd<std::mem_fun1_t<T,U,V> > >(std::bind2nd(std::mem_fun(mf), arg), log_msg);
}   

template <typename T>
class Wrapper {
    T* t; // pointer, not just a plain instance, because T may not have default constructor
public:
    Wrapper(T* _t) : t(_t) { }        

    template <typename T_mem_fun_tp>
    typename T_mem_fun_tp::result_type operator()(const T_mem_fun_tp& t_mf) {
        // Handle function object as you wish, for example print logging message
        std::cout << t_mf.log_msg << '\n';
        return t_mf(t);
    }   

    ~Wrapper() { delete t; }
};  

int main() {
    Wrapper<A> wA(new A());
    int y = wA(create_function_logged<int,A,int,&A::inc>(123, "calling A::inc from Wrapper"));
    std::cout << "wA.f(123)=" << y << '\n';
    return 0;
}

Output:

calling A::inc from Wrapper
A::inc 123
wA.f(123)=124

EDIT2: In addition there's possible to override operator->* inside Wrapper and return some kind of proxy object, that holds a pointer to the instance and a pointer to the method. With this approach you can control the moment of method's execution, as well as pre- or post- process the proxy objects. A description of this technique can be found at http://aristeia.com/Papers/DDJ_Oct_1999.pdf

like image 125
tonso Avatar answered Sep 22 '22 07:09

tonso