Вызов определения базового класса виртуальной функции-члена с указателем функции
Я хочу вызвать реализацию базового класса виртуальной функции с помощью указателя функции-члена.
class Base {
public:
virtual void func() { cout << "base" << endl; }
};
class Derived: public Base {
public:
void func() { cout << "derived" << endl; }
void callFunc()
{
void (Base::*fp)() = &Base::func;
(this->*fp)(); // Derived::func will be called.
// In my application I store the pointer for later use,
// so I can't simply do Base::func().
}
};
В приведенном выше коде функция func производного класса будет вызвана из callFunc. Есть ли способ сохранить указатель на функцию-член, который указывает на Base:: func, или мне придется каким-то образом использовать using
?
В моем реальном приложении я использую boost:: bind для создания объекта boost:: function в callFunc, который позже я использую для вызова func из другой части моей программы. Поэтому, если boost:: bind или boost:: function имеют некоторый способ обойти эту проблему, которая также поможет.
Ответы
Ответ 1
Когда вы вызываете виртуальный метод с помощью ссылки или указателя, вы всегда активируете механизм виртуального вызова, который находит наиболее производный тип.
Лучше всего добавить альтернативную функцию, которая не является виртуальной.
Ответ 2
То, что вы пытаетесь сделать, к сожалению, невозможно. Функции-указатели для-членов предназначены для поддержания виртуальности функции, на которую указывает.
Ответ 3
Ваша проблема в том, что указатель на функцию-член не совсем такой же, как указатель на функцию. Фактически это не просто указатель, но значительно более сложная структура, которая различается в деталях на уровне реализации компилятора. Когда вы вызываете его с помощью синтаксиса (this->*fp)()
, вы на самом деле вызываете его на исходном объекте, что вызывает отправку виртуальной функции.
Одна вещь, которая может работать, - это применить ее к типу указателя не метода. Это немного скрипучий, но я думаю, что он должен работать. Вам все равно нужно передать Base *
, но вы делаете это явно, а отправка виртуальной функции обходится:
typedef void BasePointer(Base*);
void callFunc()
{
BasePointer fp = (BasePointer *)&Base::func;
fp(this);
}
Обновление: Хорошо, нет, вы не можете этого сделать. Это незаконно, и не было бы безопасно, если бы оно было законным. С++ FAQ имеет подробнее об этом. Но зная, что это не решает вашу проблему. Проблема в том, что указатель-объект или указатель-к-член, если вы хотите вызвать Base::func
с помощью указателя Base
, объект, который он указывает, также должен быть Base
. Если вы можете это организовать, вы можете использовать указатель на функцию-член.
Здесь другая мысль, не красивая, но по крайней мере работоспособная. Предоставьте функцию Derived
, не виртуальную, которая явно вызывает Base::func
. Вместо этого укажите на это. Он не будет масштабироваться, если вам нужно сделать это в общем случае из множества различных вариантов func
и callFunc
, но он будет отлично работать для одного метода.
Ответ 4
Есть ли какая-либо конкретная причина для этого с помощью указателя на функцию?
Вы должны просто написать:
Base::func();
для вызова реализации базового класса.
Ответ 5
В дополнение к тому, что говорит кварк, более общее замечание состоит в том, что вы должны использовать реализацию сигнала/слота, а не голой указатель функции. У Boost есть один, там libsigc и множество других.
Ответ 6
Что случилось с этим?
(Base(*this).*fp)();
Теперь, если вы удовлетворены этим, возникает вопрос, почему вы даже используете указатель на функцию. Я думаю, что может помочь другой контекст.