обернуть виртуальный метод с несколькими подписями - PullRequest
0 голосов
/ 07 марта 2020

У меня есть класс с методом, который имеет много подписей (в приведенном ниже примере просто два для простоты).

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

и производный класс, который переопределяет методы родительского класса, добавляя некоторые логики c до и после вызова родительского метода.

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

Поскольку logi c до и после вызова родительского метода одинаков для всех переопределенных методов, я пытаюсь инкапсулировать все логи c в оболочке функции, которая принимает метод для вызова в качестве аргумента.

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<void() const>
  2. , если вы вызываете объект g внутри метода f класса B, программа вводит бесконечный l oop, который я предположил это связано с полиморфизмом, то есть виртуальная таблица разрешается в B::f вместо A::f

Есть ли у вас какие-либо предложения о том, как я могу исправить свой код, или вы знаете альтернативные способы достижения цель? * 1 025 *

Спасибо!

1 Ответ

0 голосов
/ 07 марта 2020

Это поведение, предназначенное для виртуальных функций, виртуальная таблица ДОЛЖНА БЫТЬ разрешена в B::f. Вызов явного A::f изнутри B::f не использует виртуальную таблицу.

С другой стороны, если вы можете поместить код в function_wrapper, вы можете просто вызвать эту функцию, чтобы добавить свой желаемое поведение, затем вызовите родительский метод:

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