Вызов виртуальной функции по адресу
От: Аноним  
Дата: 18.09.13 09:21
Оценка:
Вызовется ли виртуальная функция дочернего класса по указателю на функцию родительского?
Псевдокод:


class A 
{
 public:
     virtual void foo()
     {
     }
};

class B : public A
{
 public:
     virtual void foo()
     {
     }
};

A a;
void * pFunction = &а::foo;


// приводим функцию к нужному типу и вызываем (как это записать правильно? )
*(( А::foo* )pFunction )();  

// Вызовется ли здесь B::foo() ? Если нет, то как вызвать B::foo(), имея адрес A::foo() ?



Или это вообще ужос-ужос-ужос и красиво все надо писать не так?
Re: Вызов виртуальной функции по адресу
От: jazzer Россия Skype: enerjazzer
Дата: 18.09.13 09:33
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вызовется ли виртуальная функция дочернего класса по указателю на функцию родительского?

да

Только виртуальная функция всегда подразумевает объект
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Вызов виртуальной функции по адресу
От: llex  
Дата: 18.09.13 09:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вызовется ли виртуальная функция дочернего класса по указателю на функцию родительского?

А>Псевдокод:

А>

А>class A 
А>{
А> public:
А>     virtual void foo()
А>     {
А>     }
А>};

А>class B : public A
А>{
А> public:
А>     virtual void foo()
А>     {
А>     }
А>};

А>A a;
А>void * pFunction = &а::foo;


А>// приводим функцию к нужному типу и вызываем (как это записать правильно? )
А>*(( А::foo* )pFunction )();  

А>// Вызовется ли здесь B::foo() ? Если нет, то как вызвать B::foo(), имея адрес A::foo() ?

А>


А>Или это вообще ужос-ужос-ужос и красиво все надо писать не так?


http://www.rsdn.ru/article/cpp/fastdelegate.xml
Автор(ы): Don Clugston
Дата: 27.07.2005
В данной статье предоставлен исчерпывающий материал по указателям на функции-члены, а также приведена реализация делегатов, которые занимают всего две операции на ассемблере.


 Base* pBase = new Derived;
 void (Base::*pMyFuncPtr)() = &Base::Func;

(pBase->*pMyFuncPtr)();
Re: Вызов виртуальной функции по адресу
От: Кодт Россия  
Дата: 18.09.13 10:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вызовется ли виртуальная функция дочернего класса по указателю на функцию родительского?


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

http://ideone.com/QtwoEs

#include <cstdio>

struct A
{
    virtual void foo() { puts("fa"); }
    void goo()         { puts("ga"); }
};
struct B: A
{
    virtual void foo() { puts("fb"); }
    void hoo()         { puts("hb"); }
};

typedef void (A::*FA)();
typedef void (B::*FB)();

void testA(FA f)
{
  A a; (a.*f)();
  B b; (b.*f)(); // ковариантность левого операнда
}
void testB(FB f)
{
//A a; (a.*f)(); // ошибка компиляции! а вдруг справа функция, специфичная для B (hoo, например)
  B b; (b.*f)();
}

int main()
{
  testA(&A::foo); // fa, fb
  testA(&A::goo); // ga, ga - потому что невиртуальная функция
//testA(&B::hoo); // ошибка компиляции: а вдруг внутри слева объект A? (и он там, действительно, есть)
//testA(&B::foo); // ошибка компиляции: ну и что, что это переопределение, тип-то уже приподнят

  testB(&A::foo); // fb
  testB(&A::goo); // ga
  testB(&B::foo); // fb
  testB(&B::hoo); // hb
}


А>Или это вообще ужос-ужос-ужос и красиво все надо писать не так?


Указатели на члены — это недоуказатели на функции, с корявым синтаксисом и неочевидной для новичка ковариантностью типов по своему значению (fb = &A::foo) и контравариантностью — по левому аргументу (объекту). Тогда как у обычных указателей — контравариантность по значению: A* pa = pb.

Поэтому, если не хочется ломать себе голову, и если не нужно приведение типов из коробки, то лучше использовать свободные функции, стандартные замыкания и лямбды.
// в сишном стиле
void a_foo(A* a) { a->foo(); }
a_foo(&b);

// C++98-03
boost::bind(&A::foo, _1) (&b);
boost::function<void(A*)> a_foo = boost::bind(&A::foo, _1);
a_foo(&b);

// C++11
auto a_foo_1 = std::bind(&A::foo, _1);
std::function<void(A*)> a_foo_2 = a_foo;
auto a_foo_3 = [](A* a) { a->foo(); }

Синтаксис тоже страшненький, но, по крайней мере, семантика предсказуема, а главное, что она унифицирована с любыми другими свободными функциями.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.