C++ 在C++;

C++ 在C++;,c++,C++,CLOS有一个简洁的概念:before、:after和:around方法 在主方法之前调用:before方法 在主方法之后调用:after方法 在:before+primary+:after序列周围调用:around方法 :before、:after和:around方法是链接的,而不是重写的。假设父类和子类都定义了一个foo方法和:before foo方法。子对象的foo方法重写父对象的foo方法,但在调用此重写方法之前,调用子对象和父对象的:before foo方法 Python装饰器提供

CLOS有一个简洁的概念:before、:after和:around方法

  • 在主方法之前调用:before方法
  • 在主方法之后调用:after方法
  • 在:before+primary+:after序列周围调用:around方法
:before、:after和:around方法是链接的,而不是重写的。假设父类和子类都定义了一个foo方法和:before foo方法。子对象的foo方法重写父对象的foo方法,但在调用此重写方法之前,调用子对象和父对象的:before 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();
    }
};
缺点:

  • 对某些人来说,这是一种反模式
  • 它要求我在指定父类时是显式的
  • 它要求我的类的扩展程序遵循相同的范例
  • 如果我需要打电话给祖父母,因为父母没有覆盖“做某事”,那么多重继承呢
  • 它没有完全抓住CLOS的概念
我发现这些概念在我使用Flavors(CLOS的前身)时非常方便。我已经在一些地方使用了上述变通方法,一些地方将其视为反模式。(其他国家也在其他地方效仿,因此这种嘲笑并不普遍。)


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

< p>我并不是说这是等价于或与其他语言相媲美的,但是我认为非虚接口习惯用法适用于你的问题:

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()
时,总是调用最派生的
在\u foo
之前、在\u foo之后和
do\u foo

这是我可以做的,但还是有点难看

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

#包括

#定义C(s)std::cout使用
(std/boost)::shared\u ptr
可以很好地了解这方面的基础知识。详情请参阅:


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

我可能过于简化了示例。我有一个多层次的继承,每个派生类都围绕着调用父类做一些事情。不过,NVI是一种可能性。仍然很麻烦,因为它仍然需要派生类来调用父方法。为了使before_foo和after_foo的内容正确,派生类必须调用before_或after_方法的父类。Yiu H的回答更接近于模拟CLOS包装器方法的味道,但我确实喜欢NVI的想法。如果将来遇到需要CLOS概念的情况,我会记住这两个建议。谢谢。我用我的设计作为范例。我的问题更多的是好奇:如何最好地模仿CLOS:以前、之后和之后:C++中的包装方法?在CLOS中,这些包装器方法是链式的,并以特定的方式进行。很好。您将do_something设置为虚拟意味着派生类可以重写它,如果它通过调用super::do_something来重写它,那么还有CLOS:around。总的来说有点笨拙,但是由于语言不支持它,任何实现都会有点笨拙。有趣的是,特别是因为Stroustrup(简短地)乐于实现CLOS:before和:after方法的概念。
#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);
}