Подтвердить что ты не робот

Вызов определения базового класса виртуальной функции-члена с указателем функции

Я хочу вызвать реализацию базового класса виртуальной функции с помощью указателя функции-члена.

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 имеют некоторый способ обойти эту проблему, которая также поможет.

4b9b3361

Ответ 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)();

Теперь, если вы удовлетворены этим, возникает вопрос, почему вы даже используете указатель на функцию. Я думаю, что может помочь другой контекст.