Вызов виртуальной функции статически через указатель на функцию - PullRequest
5 голосов
/ 03 декабря 2010

Пожалуйста, рассмотрите следующий код.

#include <iostream>
#include <memory>

struct A {
  A() {}
  virtual void f() {
    std::cout << "A::f" << std::endl;
  }
private:
  A(const A&);
};

struct B : public A {
  virtual void f() {
    std::cout << "B::f" << std::endl;
    call(&A::f);
  }
private:
  void call(void (A::*aMethod)()) {
    // ...
    (static_cast<A&>(*this).*aMethod)();
    //(static_cast<A>(*this).*aMethod)();  -> not allowed to copy!
    // ...
  }
};

void main() {
  std::auto_ptr<B> b (new B);
  b->f();
}

Этот код рекурсивно вызывает один и тот же метод B::f, пока не выйдет из стека, в то время как я хотел бы, чтобы метод call вызывал A::f. То есть он должен называть это статически, как обычно, если бы я просто написал:

struct B : public A {
  virtual void f() {
    std::cout << "B::f" << std::endl;
    // ...
    A::f();
    // ...
  }
};

Причина, по которой я хочу использовать метод call, состоит в том, чтобы разложить некоторый код до и после «статического вызова», который является общим для нескольких методов с такой же сигнатурой, как f ...

Как статически вызвать виртуальную функцию, определенную во время выполнения?

Ответы [ 2 ]

5 голосов
/ 03 декабря 2010

Это ожидается. Выражение объекта является ссылкой на базовый класс A, и, следовательно, механизм виртуальной функции (динамическое связывание) запускается, когда A :: f является виртуальным.

Только оператор :: может подавить механизм вызова виртуальной функции.

$ 10,3 / 12- "Явная квалификация с оператор области действия (5.1) подавляет механизм виртуального вызова. "

1 голос
/ 03 декабря 2010

Ваше переопределение разрешается, когда вы берете указатель, поэтому то, что вы хотите здесь, не может быть легко таким образом. Лучшее, что вы можете сделать - это обертка, которая вызывает вашу функцию - либо внешнюю, либо не виртуальную функцию, которая вызывает вашу функцию. Если у вас есть функции C ++ 0x, вы можете использовать лямбду, которая является самым чистым решением IMO.

Возможно, вы захотите переосмыслить то, как вы выполняете функции pre / post, как еще один способ решения вашей проблемы: они могут быть реализованы путем перегрузки оператора «->».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...