在C ++中模拟CLOS:before,:after和:around

时间:2011-07-08 09:09:38

标签: c++

CLOS有一个简洁的概念:before,:after和:around around。

  • :在主方法之前调用方法之前。
  • :在主方法之后调用方法之后。
  • 围绕以下方法调用:around + primary +:after sequence。

:before,:after和:around方法被链接而不是被覆盖。假设父类和子类都定义了一个foo方法,并且:在foo方法之前。子进程的foo方法会覆盖父进程的foo方法,但会覆盖子进程和父进程:在调用这个重写方法之前调用foo方法之前。

Python装饰器提供类似于CLOS的东西:around方法。在C ++中没有这样的东西。它必须手工轧制:

class Child : public Parent {
    virtual void do_something (Elided arguments) {
        do_some_preliminary_stuff();
        Parent::do_something (arguments);
        do_some_followup_stuff();
    }
};

缺点:

  • 这是对某些人的反模式。
  • 它要求我明确指定父类。
  • 它要求我的课程的扩展者遵循相同的范例。
  • 如果我需要调用祖父母,因为父母没有覆盖do_something,以及多重继承怎么办?
  • 它并没有完全捕捉到CLOS的概念。

当我使用Flavors(CLOS的前身)时,我发现这些概念非常方便。我在一些地方使用了上述解决方法,有些人将其作为反模式挑战。 (其他人已在其他地方模仿它,因此嘲笑并不普遍。)

问题:这是否被认为是C ++中的反模式,是否有更好的解决方法?

3 个答案:

答案 0 :(得分:2)

你可以使用(std/boost)::shared_ptr很好地掌握这个基础知识。有关详细信息,请参阅此处:http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/sp_techniques.html#wrapper

获取您提到的继承行为只需要前缀/后缀函数来调用父类中的前缀/后缀函数。

答案 1 :(得分:1)

我并不是说这与其他语言相同或相当,但我认为非虚拟接口惯用法适用于您的问题:

class parent {
public:
    void foo()
    {
        before_foo();
        do_foo();
        after_foo();
    }

protected:
    // you can make those pure virtual with an implentation, too
    virtual void before_foo() { ... }
    virtual void do_foo() { ... }
    virtual void after_foo() { ... }
};

class child: public parent {
protected: // or private
    void before_foo() { ... }
    void do_foo() { ... }
    // must provide a dummy after_foo that delegates to parent::after_foo
    // if it is pure virtual in the parent class
};

在致电p.foo()时,始终会调用派生最多的before_fooafter_foodo_foo

答案 2 :(得分:1)

这是我能做的,但它仍然有点难看。

基本上我把实际的工作放在一个单独的钩子里,所以你没有在处理方法中调用pre / post钩子。在继承链中,您可以完全控制是否要添加前/后挂钩以及挂钩调用的顺序(在子挂钩之前或之后调用父挂钩)。

#include <iostream>
#define C(s) std::cout << s << std::endl;

class Parent {
    public:
    virtual void do_something(int arg) {
        do_some_pre_hook();
        do_some_hook(arg);
        do_some_post_hook();
    }
    virtual void do_some_pre_hook() {
        C("parent pre_hook");
    }
    virtual void do_some_post_hook() {
        C("parent post_hook");
    }
    virtual void do_some_hook(int arg) {
        //this is where you actually do the work
    }
};

class Child : public Parent {
    public:
    typedef Parent super;

    virtual void do_some_pre_hook() {
        super::do_some_pre_hook();
        C("Child pre_hook");
    }
    virtual void do_some_post_hook() {
        super::do_some_post_hook();
        C("Child post_hook");
    }
};

class GrandChild : public Child {
    public:
    typedef Child super;

    virtual void do_some_pre_hook() {
        super::do_some_pre_hook();
        C("GrandChild pre_hook");
    }
    virtual void do_some_post_hook() {
        super::do_some_post_hook();
        C("GrandChild post_hook");
    }
    virtual void do_some_hook(int arg) {
        //this is where you actually do the work
        C("GrandChild hook");
    }
};

int main() {
    GrandChild gc;
    gc.do_something(12);
}

注意:理想情况下,你会为​​这样的任务使用AOP c ++编译器或编译器扩展,但是上次我尝试它时它不太稳定......