【问题标题】:wrap a virtual method with multiple signatures用多个签名包装一个虚拟方法
【发布时间】:2020-06-20 00:47:29
【问题描述】:

我有一个类,它的方法有很多签名(在下面的示例中,为了简单起见,只有两个)。

class A
{
public:
    virtual void f(int x) const
    {
        std::cout << "A::f(" << x << ")\n";
    }

    virtual void f(int x, int y) const
    {
        std::cout << "A::f(" << x << "," << y << ")\n";
    }
};

还有一个派生类,它覆盖了父类的方法,在调用父类方法之前和之后添加了一些逻辑。

class B : A
{
public:
    void f(int x) const override
    {
        std::cout << "B::f(" << x << ")\n";

        // do some stuff before the call
        A::f(x);
        // do some stuff after the call
    }

    void f(int x, int y) const override
    {
        std::cout << "B::f(" << x << "," << y << ")\n";

        // do some stuff before the call
        A::f(x, y);
        // do some stuff after the call
    }
};

由于调用父方法之前和之后的逻辑在所有重写的方法中都是一致的,因此我试图将所有逻辑封装在一个函数包装器中,该函数包装器将要调用的方法作为参数。

void wrapper(B const *b, std::function<void() const> &f)
{
    std::cout << "wrapper(" << b << "," << &f << ")\n";

    // do some stuff before the call
    f();
    // do some stuff after the call
}

class B : A
{
public:
    void f(int x) const override
    {
        std::cout << "B::f(" << x << ")\n";

        A const *p = this;
        auto g = std::bind(static_cast<void (A::*)(int) const>(&A::f), p, x);
        wrapper(this, g);
    }

    void f(int x, int y) const override
    {
        std::cout << "B::f(" << x << "," << y << ")\n";

        A const *p = this;
        auto g = std::bind(static_cast<void (A::*)(int, int) const>(&A::f), p, x, y);
        wrapper(this, g);
    }
};

我的代码有(至少)两个问题,

  1. std::bind 不会生成所需的 std::function&lt;void() const&gt;
  2. 如果你在类B的方法f中调用对象g,程序进入一个无限循环,我猜这是由于多态性,即虚拟表解析为B::f而不是A::f

您对如何修复代码有任何建议,或者您知道实现目标的替代方法吗?

谢谢!

【问题讨论】:

    标签: c++ oop functional-programming polymorphism overriding


    【解决方案1】:

    这是虚函数的预期行为,虚表必须解析为B::f。从B::f 内部对显式A::f 的调用不使用虚拟表。

    另一方面,如果你可以将代码放在function_wrapper 中,你可以简单地调用这个函数来添加你想要的行为,然后调用父方法:

    class B : public A
    {
    public:
      void f(int x) const override
      {
        do_otherstuff();
        A::f(x);
      }
    }
    

    【讨论】:

    • 感谢您的回答。这正是我现在处理任务的方式,两个方法分别在父方法调用之前和之后调用。我希望用一个包装函数替换它们。
    • 在某一时刻,你无论如何都得打电话给他们。如果你真的有长时间重复的任务,你总是可以使用宏
    猜你喜欢
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    相关资源
    最近更新 更多