Russian Qt Forum
Ноябрь 23, 2024, 05:19 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Делегаты С++ в классах-наследниках  (Прочитано 16287 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #15 : Декабрь 29, 2014, 13:00 »

Ладно упрощу вопрос:

Есть базовый класс
Код:
class CBaseClass {

 //приватные данные для этого класса
 int private_base_data;

 {virtual?} void click(ClassA * param)  = 0;//сигнатура обработчика

 QHash<QString,click> hash;

 void registerClick(QString name, click func) { hash[name]=func; }

 void callClick(QString name, ClassA * objectA) {
 click func = hash.value(name);
 if(func)
 func(objectA);
 }

};

Есть наследованный класс
Код:
class CDerivedClass : public CBaseClass 
{
 int private_derived_data;

 void click1(ClassA * param);
 void click2(ClassA * param);
 ...
 void clickN(ClassA * param);
};

class CDerivedClass2 : public CDerivedClass
{
 int private_derived2_data;
 void click2_1(ClassA * param);
 ...
 void click2_N(ClassA * param);
};

Что я хочу получить: что бы можно было регистрировать в хеше функции обработчики, и потом их вызывать по имени и эти функции видели данные всех классов от базового до текущего.
К сожалению сейчас это все реализовано через статические функции-члены что не совсем удобно. По сути это замена switch оператора, только параметр строковый. т.е. функции обработчику соотвествует определенное название в виде строки, и когда она приходит, нужно вызвать соотвествующий член-функцию, передать ей параметр и что бы функция вызвалась в том классе, в котором она описана а не в базовом (когда все private_derived..data не видны).
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


Просмотр профиля
« Ответ #16 : Декабрь 29, 2014, 13:06 »

печально, но в моей версии 5.3.2 std::function не нашлось Грустный
std::function, это не Qt, это стандартные либы C++

Если у вас gcc добавьте опцию компилятора: -std=c++11
Если msvc то версия должна быть не меньше 2010 (в опциях ничего не надо добавлять).
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #17 : Декабрь 29, 2014, 13:10 »

в Qt редакторе при компиляции ругается и подчеркивает как ненайденный элемент.
« Последнее редактирование: Декабрь 29, 2014, 13:12 от Fregloin » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Декабрь 29, 2014, 13:23 »

Что я хочу получить: что бы можно было регистрировать в хеше функции обработчики, и потом их вызывать по имени и эти функции видели данные всех классов от базового до текущего.
По-моему не хватает только virtual.

А как вы хотели что-то узнать не читая?
Почитайте исходники того же std::function, общее представление может дать, не смотря на наличие С++11, но опять же там тоже много текста.
Пример: указатель на ф-цию член. Тут все ясно - хранится адрес ф-ции (чуть по-другому для virtual). А что в случае std::function? Тоже хранится адрес ф-ции или только объекта или как? Вот Вы много читали, объясните please
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


Просмотр профиля
« Ответ #19 : Декабрь 29, 2014, 13:29 »

в Qt редакторе при компиляции ругается и подчеркивает как ненайденный элемент.
Какой компилятор?

Пример: указатель на ф-цию член. Тут все ясно - хранится адрес ф-ции (чуть по-другому для virtual). А что в случае std::function? Тоже хранится адрес ф-ции или только объекта или как?
тут описание и хорошие примеры:
http://ru.cppreference.com/w/cpp/utility/functional/function
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #20 : Декабрь 29, 2014, 13:31 »

вот такой
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #21 : Декабрь 29, 2014, 13:34 »

ага, прописал в mkspecs/win32-g++

QMAKE_CFLAGS = -std=c++11

собралось
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


Просмотр профиля
« Ответ #22 : Декабрь 29, 2014, 13:35 »

вот такой
1. я не уверен, но возможно там кавычки не нужны
2. выполнить qmake

можно в pro файл добавить строку:
Код:
gcc:QMAKE_CXXFLAGS += -std=c++11
и выполнить qmake
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Декабрь 29, 2014, 13:43 »

тут описание и хорошие примеры:
http://ru.cppreference.com/w/cpp/utility/functional/function
Ну то я читал не раз, правда в чуть др редакции http://www.cplusplus.com/reference/functional/function/. Да. хорошее описание и примеры, вообще - прекрасный справочник. Но это "как юзать" - а я хотел узнать о внутреннем механизме. Ладно, "понял, отстал"  Улыбающийся

ага, прописал в mkspecs/win32-g++
Наверное можно и std::function, но и обычный указатель на ф-цию член (без С++ 11) должен работать
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #24 : Декабрь 29, 2014, 13:47 »

обычный указатель на функцию-член работает только в классе, в котором он описан. В наследниках уже такое не прокатит, проверено.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #25 : Декабрь 29, 2014, 15:14 »

никак не могу разобраться с std::bind, std::function.
Нашёл простые примеры, но толку с них для меня не много.

Вот что я пытаюсь сделать
Код:
class QRailItem; //графический элемент на сцене

class CBaseController {
   typedef  std::function<void(QRailItem*)> ClickHandlerFunc;
   QHash<QString,ClickHandlerFunc>                   fclickHahdlers;
protected:
   void    setClickHandlerForButton(const QString & role, ClickHandlerFunc handler);
private slots:
   void    handleViewItemClick();      //обработка нажатия на граф.объект
};

void CBaseController ::setClickHandlerForButton(const QString &role, CRailController::ClickHandlerFunc handler)
{
    fclickHahdlers[role] = handler;
}

void CRailController::handleViewItemClick()
{
    QRailItem       *   railItemView = qobject_cast<QRailItem*>(sender());  //получаем отправителя
    if(railItemView && railItemView->controllerLink())                      //если есть
    {
        try
        {
            ClickHandlerFunc func = fclickHahdlers.value(railItemView->referenceRole());
            if(func)
                func(railItemView);
        }
        catch(std::bad_function_call call)
        {
            qDebug("bad function call %s",call.what());
        }
    }
}

Теперь я объявляю наследника
Код:
class CDerivedController : public CBaseController
{
    void    sendCommandI(QRailItem *eventSource);
    void    sendCommandOI(QRailItem *eventSource);
    void    sendCommandZP(QRailItem *eventSource);
}

CDerivedController::CDerivedController():CBaseController()
{
    ClickHandlerFunc    f = std::bind(&CRailCrossController::sendCommandI);//ругатется здесь
    setClickHandlerForButton(iBtnRole,f);
}

Подскажите как правильно мне все сделать...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #26 : Декабрь 29, 2014, 15:50 »

обычный указатель на функцию-член работает только в классе, в котором он описан. В наследниках уже такое не прокатит, проверено.
Не раз использовал, работает. И должен работать - иначе зачем бы этот указатель имел поддержку вызова виртуалов (а он ее имеет)
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #27 : Декабрь 29, 2014, 16:47 »

Покажите пример, потому что я пробовал делать как вы говорите, не работает
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Декабрь 29, 2014, 17:28 »

Покажите пример, потому что я пробовал делать как вы говорите, не работает
Код
C++ (Qt)
#include <QtCore>
#include <QDebug>
 
struct Base {
typedef void (Base::*MemberFunc)( int );
 
Base( void )
{
mHash["DoPrn"] = &Base::DoPrn;
}
 
virtual void DoPrn( int val )
{
qDebug() << "Base DoPrn" << val;
}
 
void CallByName( const QString & name, int val )
{
MemberFunc func = mHash.value(name);
if (func) (this->*func)(val);
}
 
QHash<QString, MemberFunc> mHash;
};
 
struct Derived : public Base {
virtual void DoPrn( int val )
{
qDebug() << "Derived DoPrn" << val;
}
};
 
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
 
Derived test;
test.CallByName("DoPrn", 5);
 
   return 0;
}
 
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #29 : Декабрь 29, 2014, 20:43 »

Выше всё уже показали же..  Это делается с помощью std::function + std::bind

Код
C++ (Qt)
using namespace std::placeholders;
 
class base
{
public:
   template <class T, class M>
   void register_delegate(const std::string & name, T *obj, M delegate)
   {
       _map[name] = std::bind(delegate, obj, _1, _2);
   }
 
   void run(const std::string & name, int a, int b)
   {
       _map[name](a, b);
   }
 
private:
   std::map<std::string, std::function<void(int, int)>> _map;
};
 
class derived : public base
{
public:
   void delegate(int a, int b)
   {
       std::cout << "derived::delegate(int a, int b); a + b = " << a + b << std::endl;
   }
 
   void delegate2(int a, int b)
   {
       std::cout << "derived::delegate2(int a, int b); a * b = " << a * b << std::endl;
   }
};
 
 
 
   derived d;
   d.register_delegate("id1", &d, &derived::delegate);
   d.register_delegate("id2", &d, &derived::delegate2);
 
   d.run("id1", 1, 2);
   d.run("id2", 1, 2);
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.189 секунд. Запросов: 23.