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

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

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

Сообщений: 1025


Просмотр профиля
« : Декабрь 26, 2014, 16:14 »

Привет, кто то сталкивался с делегатами в с++ и как их использовать в наследуемых классах?
Нашёл пока только описание толковое для делегатов одного класса. С наследованием проблемы...

По сути что надо.

Есть класс базовый
Код:
class Base {
   typedef void (Base::*delegate)(SomeClass1 * obj1, SomeClass2 * obj2); //сигнатура делегата
   QHash<QString,delegate>  fdelegateHash;
protected:
  void registerDelegate(const QString & delegateId, delegate delegatePtr);
public:
void   executeDelegate(const QString & delegateName, SomeClass1 * obj, SomeClass2 * obj2);
};

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

В этом и проблема, что с данной сигнатурой я могу регистрировать делеагты созданные в базовом классе, а с наследником уже не получается.
Либо через reinpret_cast<BaseClass::delegate>. Тогда вызываемый делегат наследника видит только ту часть объекта, которая соответствует классу Base.

Знаю что есть подобній функционал в boost, но я не хочу его за собой тянуть (ради одной функции тянуть все зависимости).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Ладно, не постесняюсь спросить Улыбающийся  А разве "делегат" какой-то стандартный термин в плюсах? (никогда не слышал о таком). По тексту я вижу просто указатель на ф-цию член. Если в базовом классе она не виртуальна - получите именно то что описываете
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


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

Ладно, не постесняюсь спросить Улыбающийся  А разве "делегат" какой-то стандартный термин в плюсах?

Да.

см std::function
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



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

Если я правильно понял, чего хочет ТС, то придётся шагнуть чуть дальше, чем просто std::function)
Записан

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

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Да.

см std::function
Смотрю http://www.cplusplus.com/reference/functional/function/, слова "delegate" там нет. Ладно, не суть "как называется", поясните какой смысл вкладывается здесь в этот термин

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

Сообщений: 339


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

На RSDN есть статья "Указатели на функции-члены и реализация самых быстрых делегатов на С++."
Если я не ошибаюсь, там решался этот вопрос:
В этом и проблема, что с данной сигнатурой я могу регистрировать делеагты созданные в базовом классе, а с наследником уже не получается.
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


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

поясните какой смысл вкладывается здесь в этот термин

Делегат - средство опосредованного вызова функции, либо функции-члена.
Обычно, с возможностью биндинга аргументов, с которыми нужно выполнить вызов.

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

При помощи делегатов реализуются технологии "системы сообщений", "слоты-сигналы" и тп.

Пример:

http://rextester.com/VASRI32220


Код:
#include <iostream>
#include <functional>
using namespace std;

//предположим у нас есть GUI библиотека
//при помощи которой мы можем создавать кнопки
//однако такие библиотечные классы ничего не знают о классах целевого бизнес-приложения
struct Button
{
    typedef std::function<void()>
        EventClick;
   
    EventClick mEventClick;
   
    //имитируем "клик" на кнопке.
    void SimulationClick()const
    {
        cout<<"GUI: Click!\n";
       
        //когда кнопка впадает в состояние "меня кликнули",
        //она должна испустить сигнал - предупредить о факте клика заинтересованные объекты бизнес-приложения.
       
        //делегат позволяет зделать это, без необходимости знать о точных типах получателей события
        if(mEventClick)
            mEventClick();
    }
   
};


//а этот класс - часть бизнес-модели приложения
//модель никак не связанна с GUI, и ничего не знает о её классах
//ровно, как и GUI ничего не знает о модели
struct Model
{
    //модель реализует поведение на нажатие кнопки.
    //точный тип кнопки при этом не имеет значение.
    //природа источника события не имеет значения.
    void OnClick()const
    {
        cout<<"Model:button was click\n";
    }
};


//бизнес-приложение
int main()
{
    std::cout << "Hello, world!\n";
   
    //здесь мы создаем GUI, и модель.
    //И устанавливаем между ними связь.
   
    //Обратите внимание:
    //изначально, ни модель ни GUI не подозревают о существовании друг друга.
   
    //Для организации взаимодействия между ними используется технология делегатов.
   
    Button button;
    Model model;
   
   
    //заряжаем делегат.
    button.mEventClick = [&model](){ model.OnClick(); };
   
    //теперь, когда на кнопку нажмут, она дернет делегат, который дернет лямбду, которая дернет модель.
   
   
    // есть и другие способы передачи сигнала. Например:
    button.mEventClick = std::bind(&Model::OnClick, &model);
   
    //используя шаблонную магию, бинд генерирует функтор, по своему действию аналогичный лямбде.
    //суть проста: std::function это просто тонкая обертка над функторами,
    //которые дергают функции или функции-члены получателей сообщения
   
    //теперь имитирует нажатие на кнопку:
   
    button.SimulationClick();
}
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


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

Если я правильно понял, чего хочет ТС, то придётся шагнуть чуть дальше, чем просто std::function)

Если я правильно понял ТС, то он изобретает именно std::function.

Он не хочет цеплять boost::function, потому что не хочет тащить буст.
Однако, видимо он просто не в курсе, что boost::function официально узаконили.
И он вошел в стандарт с++11

Теперь он доступен, как std::function.

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Код:
    //заряжаем делегат. 
    button.mEventClick = [&model](){ model.OnClick(); };
   
    //теперь, когда на кнопку нажмут, она дернет делегат, который дернет лямбду, которая дернет модель.
   
   
    // есть и другие способы передачи сигнала. Например:
    button.mEventClick = std::bind(&Model::OnClick, &model);
}
Т.е. в обоих случаях адрес model хранится в структуре function которая умеет вызывать и ф-цию-член?
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


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

Т.е. в обоих случаях адрес model хранится в структуре function которая умеет вызывать и ф-цию-член?

std::function - тонкая обертка над функторами. Она хранит объект-функтор по значению.

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

В общем, вы можете скормить std::function любой функтор, какой захотите.
Главное - что бы его operator() отвечал сигнатуре функции.

Пример:
http://rextester.com/DKA83721

Код:
#include <iostream>
#include <functional>
using namespace std;


struct CustomFunctor
{
    bool operator()(int v)const { return v%2 == 0; }
};

int main()
{
    std::cout << "Hello, world!\n";
    
    
    //умеет запускать любые функции/функции-члены
    //которые возвращают тип bool
    //и принимают тип int
    typedef std::function<bool(int)>
        Executer;
    
    
    //инициализируем делегат кастомным функтором
    
    //ПРИМЕЧАНИЕ: operator() функтора
    //должен соотвествовать типу функции bool(int)
    //проверка типов выполняется времени компиляции
    
    Executer ex = CustomFunctor();
    
    
    //теперь можно запускать
    const bool result1 = ex(10);
    const bool result2 = ex(11);
    
    if(result1)
        cout<<"ex(10) is true\n";
    else
        cout<<"ex(10) is false\n";
    
    if(result2)
        cout<<"ex(11) is true\n";
    else
        cout<<"ex(11) is false\n";
}

Но обычно никто кастомные функторы не делает.

В основном используют std::bind,
который при помощи шаблонной магии генерирует функтор заточенный под вызов для конкретного объекта
При этом объект можно сохранять по ссылке/значению/смарт-поинтер  (насчет смарта не уверен).

Ну лямбда - это понятно, это функтор который будет делать то, что вы сами там пропишите.

« Последнее редактирование: Декабрь 28, 2014, 15:49 от _Bers » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

В основном используют std::bind,
который при помощи шаблонной магии генерирует функтор заточенный под вызов для конкретного объекта
Да, с bind хорошо. А вот этот сам "объект-функтор" - он "физически" существует, или это темплейт-подстава? (наверное подстава). Напр нет С++ 11, как самостоятельно получить тот же ф-ционал? (просто с целью уяснить)

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

Сообщений: 339


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

Напр нет С++ 11, как самостоятельно получить тот же ф-ционал?
повторюсь:
На RSDN есть статья "Указатели на функции-члены и реализация самых быстрых делегатов на С++."
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

И что? Все должны читать много страниц довольно субъективного текста, еще и почти десятилетней давности?  Улыбающийся
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


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

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

Сообщений: 1025


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

печально, но в моей версии 5.3.2 std::function не нашлось Грустный
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


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