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

StackOverflow https://stackoverflow.com/questions/1207106

Вопрос

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

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().
    }
};

В приведенном выше коде реализация производного класса будет вызываться из callFunc. Есть ли способ сохранить указатель на функцию-член, который указывает на Base :: func, или мне придется каким-то образом использовать using ?

В моем реальном приложении я использую boost :: bind для создания объекта boost :: function в callFunc, который я позже использую для вызова func из другой части моей программы. Так что, если boost :: bind или boost :: function найдут способ обойти эту проблему, это также поможет.

Это было полезно?

Решение

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

Лучше всего добавить альтернативную функцию, которая не является виртуальной.

Другие советы

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

Ваша проблема в том, что указатель на функцию-член не совсем совпадает с указателем на пустую функцию. На самом деле это не просто указатель, а значительно более сложная структура , который варьируется в деталях на уровне реализации компилятора. Когда вы вызываете его через синтаксис (this- > * fp) () , вы фактически вызываете его для исходного объекта, что вызывает диспетчеризацию виртуальной функции.

Единственное, что может сработать, это привести его к типу указателя, не относящемуся к методу. Это немного скрипит, но я думаю, что это должно работать. Вам все еще нужно передать Base * , но вы делаете это явно, и отправка виртуальной функции пропускается:

typedef void BasePointer(Base*);

void callFunc()
{
    BasePointer fp = (BasePointer *)&Base::func;
    fp(this);
}

Обновление: Хорошо, нет, вы не можете сделать это таким образом. Это незаконно и не будет безопасно, если это будет законно. В FAQ по C ++ есть подробнее об этом . Но зная, что это не решит вашу проблему. Проблема в том, что указатель на объект или указатель на член, если вы хотите вызвать Base :: func через указатель Base , объект, на который он указывает также быть Base . Если вы можете это организовать, то можете использовать указатель на функцию-член.

Вот еще одна мысль, не красивая, но по крайней мере выполнимая. Предоставьте в Derived функцию, не виртуальную, которая явно вызывает Base :: func . Вместо этого укажите на это. Он не будет масштабироваться, если вам нужно сделать это в общем случае большого количества различных вариантов func и callFunc , но он будет отлично работать для одного метода.

Есть ли какая-то конкретная причина для этого через указатель на функцию?

Вы должны просто написать:

Base::func();

для вызова реализации базового класса.

В дополнение к тому, что говорит кварк, более общим замечанием является то, что вы должны использовать реализацию сигнал / слот, а не пустой указатель на функцию. У Boost есть один, есть libsigc и куча других.

Что с этим не так?

(Base(*this).*fp)();

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top