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

С++: указатель на мономорфную версию виртуальной функции-члена?

В С++ можно получить указатель на (нестационарную) функцию-член класса, а затем вызвать его на объект. Если функция была виртуальной, вызов динамически отправляется динамически в зависимости от динамического типа объекта. Также возможно (не используя указатель-член) для вызова виртуальных функций-членов объектов мономорфно, явно предоставляя область, содержащую используемую версию. Следующий код демонстрирует это:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

int main( int, char** )
{
    Foo *foo = new Foo2;

    void (Foo::*foo_pointer)() = &Foo::foo;

    foo->foo();            // prints 2
    foo->Foo::foo();       // prints 1
    (foo->*foo_pointer)(); // prints 2
}

Что я хотел бы сделать, это объединить эти два и получить указатель на мономорфную версию функции-члена; то есть я хочу указатель на Foo:: foo, который всегда вызывает версию базового класса foo и печатает 1, даже если он вызывается на Foo2. Однако я не смог найти способ сделать это. Возможно ли это?

(Помимо утомительного ручного способа написания новой не виртуальной функции, которая делает мономорфный вызов, а затем получения указателя на это.)

4b9b3361

Ответ 1

Это возможно в GCC, но способ, который он документировал в разделе расширений языка С++, не предлагает переносного способа сделать это.

Вы можете сделать две вещи:

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

Ответ 2

Другими словами: вы хотите обмануть.

Нет, это невозможно, потому что так работает полиморфизм в сочетании с указателем на метод члена.

Ответ 3

Чтобы разработать пример кода для функции обертки (и, несмотря на то, что OP хотел избежать этого метода!), как во многих случаях это прагматически предпочтительное решение:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

void monomorphicFooFoo( Foo * f ) { f->Foo::foo(); }

int main()
{
    Foo *foo = new Foo2;

    void (*baseFoo)( Foo * ) = &monomorphicFooFoo;
    baseFoo( foo ); // Prints 1
}