Russian Qt Forum

Qt => Общие вопросы => Тема начата: sergek от Октябрь 07, 2014, 23:30



Название: Указатели на методы производных классов
Отправлено: sergek от Октябрь 07, 2014, 23:30
Коллеги,
нужно с помощью функции базового класса вызывать невиртуальные функции производного класса. Виртуальные использовать не хотелось бы, т.к. в разных производных классах используются разные функции, хотя и с одинаковой сигнатурой. Поэтому загромождать базовый класс не хотелось бы. Хотя этот вариант тоже остается.
Один из вариантов такой:
Код:
class Unit
{
protected:
    typedef void (Unit::* PtrFun)();
    typedef QMap<int,PtrFun> Operations;
    Operations operations;

public:
    virtual ~Unit() {}

    void run(int n){
        PtrFun fun=operations.value(n,0);
        if(fun)
            (this->*fun)();
    }
};

class Relay : public Unit
{
public:
    Relay(){
        operations[1] = PtrFun(&Relay::on);
        operations[2] = PtrFun(&Relay::off);
    }

    void on();
    void off();
};
Используется это так:
Код:
    unit = new Relay();
    unit->run(1);
    unit->run(2);
Компилятор приходится нагибать явным приведением типа (PtrFun(&Relay::on)), но, вроде бы, это не должно выстрелить - указатель &Relay::on является смещением в адресном пространстве объекта Relay, и приведение типа не должно изменить его значение. А вызов функции связан с объектом этого типа (this указывает на объект Relay).
Коллеги, на ваш взгляд, можно ли без опаски использовать такое?


Название: Re: Указатели на методы производных классов
Отправлено: Old от Октябрь 08, 2014, 01:59
А почему не использовать std::function + std::bind?


Название: Re: Указатели на методы производных классов
Отправлено: Igors от Октябрь 08, 2014, 09:10
указатель &Relay::on является смещением в адресном пространстве объекта Relay,
Если метод on не виртуальный то по-моему просто адрес ф-ции. Так часто делают в С где нет virtual, разница в досылке this


Название: Re: Указатели на методы производных классов
Отправлено: sergek от Октябрь 08, 2014, 09:56
А почему не использовать std::function + std::bind?
Спасибо, слишком сложно и мутно.. Уж проще в базовом классе объявить виртуальные пустышки, а в наследнике тогда написать честные
Код:
        operations[1] = &Unit::on;
        operations[2] = &Unit::off;
А по сути вопроса?


Название: Re: Указатели на методы производных классов
Отправлено: sergek от Октябрь 08, 2014, 09:59
Если метод on не виртуальный то по-моему просто адрес ф-ции.
Увы, это не так. Адрес функции-члена связан всегда с объектом. Иначе как бы эта функция работала с членами-данными класса?


Название: Re: Указатели на методы производных классов
Отправлено: Old от Октябрь 08, 2014, 10:26
Сложно и муторно?
/* Писал прямо здесь - могут быть опечатки. */
Код
C++ (Qt)
class Unit
{
protected:
   typedef QMap<int,std::function> Operations;
   Operations operations;
 
public:
   virtual ~Unit() {}
 
   void run(int n)
   {
       operations[ n ]();
   }
};
 
class Relay : public Unit
{
public:
   Relay(){
       operations[1] = std::bind( &Relay::on, this );
       operations[2] = std::bind( &Relay::off, this );
   }
 
   void on();
   void off();
};
 


Название: Re: Указатели на методы производных классов
Отправлено: Igors от Октябрь 08, 2014, 11:40
Увы, это не так. Адрес функции-члена связан всегда с объектом. Иначе как бы эта функция работала с членами-данными класса?
По-моему никак не связан. Хранится адрес + дельта. Адреc для не виртуала - просто адрес, для виртуала - смещение в VMT. Дельта роялит только для множественного наследования, иначе нулевая (хоть виртуал хоть нет).

Примечание: следующее предложение - просто что я видел в отладчике (т.е. не факт)
При вызове если адрес (первое поле) четный - невиртуал, нечетный - виртуал, и там разбирается.


Название: Re: Указатели на методы производных классов
Отправлено: sergek от Октябрь 08, 2014, 12:05
Сложно и муторно?
/* Писал прямо здесь - могут быть опечатки. */
std::function это шаблон, не так ли? Поэтому не хватает еще одного typedef.
Но у меня все рабно не получилось. Это, случаем, не C++11? Простого инклуда <functional> не хватает.


Название: Re: Указатели на методы производных классов
Отправлено: Old от Октябрь 08, 2014, 12:08
Это, случаем, не C++11? Простого инклуда <functional> не хватает.
Да, если у вас более ранний стандарт, то тоже есть в boost - хедеронли.


Название: Re: Указатели на методы производных классов
Отправлено: sergek от Октябрь 08, 2014, 12:12
По-моему никак не связан.
Вызов функции-члена по указателю может быть произведен только с использованием указателя на объект p->*fun() либо самого объекта obj.*fun() и никак иначе.


Название: Re: Указатели на методы производных классов
Отправлено: Igors от Октябрь 08, 2014, 12:30
Вызов функции-члена по указателю может быть произведен только с использованием указателя на объект p->*fun() либо самого объекта obj.*fun() и никак иначе.
Само собой, но никаких данных экземпляра указатель на ф-цию не хранит. Он умеет находить адрес в VMT - и то в случае виртуала. Поэтому не вижу какая опасность Вам угрожает  :)


Название: Re: Указатели на методы производных классов
Отправлено: sergek от Октябрь 08, 2014, 13:33
Ну и славно.