通用对象包装器

时间:2015-03-13 20:35:57

标签: c++

我想知道是否有一个好的,通用的方法来编写一个对象包装器,这样你就可以调用它包装在包装类本身上的类定义的所有方法(无需显式重新定义包装类中的类接口)。例如,两个不同的任意类:

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...
};

我喜欢一个通用定义的包装类,以便我可以这样做:

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

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

使用&#39; Wrapper&#39;足够通用,能够处理包装器类,并将对它进行的所有调用转发给它的内部委托。

我已经看过类似工厂模式的代码,其中使用可变参数,通用工厂可以实例化任何类,以及概括绑定到单个成员方法,但没有任何内容为全班做了。在我看来,这是不可能的......但是SO上的人会想出各种我从未想过的东西:)

编辑: 我试图通过省略不必要的细节来保持问题的简单,但我遗漏了太多。我需要包装器在每次调用时插入一些逻辑。比如说,我希望这个包装器能够计算除了将调用转发给内部对象之外还调用每个方法的次数。

EDIT2: 具体来说,我试图编写一个通用的包装器来实现ActiveObject模式。我最终做了一个活跃的&#39;基类处理公共位(管理内部线程,排队函数调用)和为每个内部类型编写子类(模拟其接口)。

EDIT3: @ id256的答案非常有趣,我想我会在某个时候回来并尝试一下这个方法。

4 个答案:

答案 0 :(得分:3)

很有可能,您可以在operator->类模板中定义Wrapper。实际上这可能看起来像:

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

这种方法用于,例如,STL的std::auto_ptr实施 - 看看http://www.cplusplus.com/reference/memory/auto_ptr/

编辑:如果你需要通过包装器对象为调用添加一些逻辑,那么上面的解决方案是不可接受的。但是你可以尝试一些与模板相结合的功能特性(尽管这种方法相当棘手):

#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;
}

输出:

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

EDIT2:此外,还可以覆盖operator->*内的Wrapper并返回某种代理对象,该对象包含指向该实例的指针和指向该方法的指针。使用此方法,您可以控制方法执行的时刻,以及代理对象的预处理或后处理。可以在http://aristeia.com/Papers/DDJ_Oct_1999.pdf

找到对此技术的描述

答案 1 :(得分:2)

如果您无法从T继承,则可能会覆盖 - &gt;运算符以授予对包装类的访问权限

class Wrapped { 
public: 
    void DoSomething(); 
}; 

template<class T>  
class Wrapper { 
public: 
    T * operator->() { 
        return &t; 
    } 

private: 
    T t; 
}; 

int main() { 
    Wrapper<Wrapped> w; 
    w->DoSomething(); 
} 

答案 2 :(得分:2)

它没有特别封装,但您可以使用一个带有成员函数指针和可变参数包的函数模板:

template<typename Inner>
class Wrapper {
 private:
  Inner inner;
 public:

  template<typename ...Args>
  Wrapper(Args&&... args) : inner(std::forward<Args>(args)...) { }

  template<typename ...Args, typename R>
  R forward( R (Inner::* function)(Args...), Args &&...args) {
    return (inner.*function)(std::forward<Args>(args)...);
  }
};


Wrapper<InnerExample1> wrapper1(1, true);
wrapper1.forward(&InnerExample1::DoSomething1, 42);
bool result = wrapper1.forward(&InnerExample1::DoSomething2, false);

Live demo

答案 3 :(得分:0)

根据你的评论(和编辑),你可以得到的最接近的是在调用方法(或访问属性)之前做一些逻辑,利用运算符 - &gt;的事实。必须在右侧使用方法或属性名称。不幸的是,你无法分辨它是哪一个。

#include <iostream>

template<typename T>
class wrapper {
  T obj;
  public:
  T* operator->() {
    std::cout << "Method called(or attribute accessed). Can't tell which one." << std::endl;
    return &obj;
  }
};

struct wrapped {
  void do_nothing() {}
};

int main() {
  wrapper<wrapped> a;
  a->do_nothing();
}