Александр Шаргин

Делегаты на C++

Введение

Делегаты - это объектно-ориентированные указатели на функции, используемые для callback-вызовов в среде CLR фирмы Microsoft. Делегат можно связать со статической функцией или с нестатическим методом любого класса (единственное условие - совпадение сигнатуры метода с сигнатурой, указанной в описании делегата). Затем связанную с делегатом функцию или метод можно вызывать, используя стандартный синтаксис вызова функции в C++. Несколько делегатов можно связать в цепочку. Благодаря этому можно 'одним махом' вызвать все связанные с ними callback-функции. Следующий пример демонстрирует применение делегатов в языке C#.

using System;

using System.IO;

namespace CSharpDelegates {

 class App {

  // Определяем делегат Callback,

  // который принимает 1 параметр и ничего не возвращает.

  public delegate void Callback(string str);

  // Это метод класса App.

  public void OutputToConsole(string str) {

   Console.WriteLine(str);

  }

  // А это статический метод класса App.

  public static void OutputToFile(string str) {

   StreamWriter sw = new StreamWriter('output.txt', true);

   sw.WriteLine(str);

   sw.Close();

  }

  public static void Main(string[] args) {

   App app = new App();

   // Создаём делегат.

   App.Callback callback = null;

   if (callback != null) callback('1');

   // Добавляем ссылку на OutputToFile.

   // Вызываем её через делегата.

   callback += new App.Callback(App.OutputToFile);

   if (callback != null) callback('2');

   // Добавляем ссылку на OutputToConsole.

   // Вызывается вся цепочка:

   // сначала OutputToFile, потом OutputToConsole.

   callback += new App.Callback(app.OutputToConsole);

   if (callback != null) callback('3');

   // Убираем ссылку на OutputToFile.

   // Вызывается только OutputToConsole.

   callback -= new App.Callback(App.OutputToFile);

   if (callback!= null) callback('4');

   // Убираем оставшуюся ссылку на OutputToConsole.

   callback -= new App.Callback(app.OutputToConsole);

   if (callback != null) callback('5');

  }

 }

}

Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках 'чистого' C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.

Частное решение

Для начала создадим делегат для callback-вызова функций и методов с простейшей сигнатурой void(void). Интерфейс этого делегата будет выглядеть так.

class IDelegateVoid {

public:

 virtual ~IDelegateVoid() {}

 virtual void Invoke() = 0;

 virtual bool Compare(IDelegateVoid* pDelegate) = 0;

};

Invoke используется для вызова функции или метода, связанного с делегатом, а Compare сравнивает 2 делегата и возвращает true, если они связаны с одной и той же функцией (методом). Очевидно, что реализация интерфейса IDelegateVoid будет отличаться для статических функций и нестатических методов класса, поэтому мы разнесём эти реализации по различным классам. Класс CStaticDelegateVoid будет 'отвечать' за статические функции, а класс CMethodDelegateVoid - за нестатические методы.

Класс CStaticDelegateVoid просто инкапсулирует указатель типа void (*)() :

class CStaticDelegateVoid: public IDelegateVoid {

public:

 typedef void (*PFunc)();

 CStaticDelegateVoid(PFunc pFunc) { m_pFunc = pFunc; }

 virtual void Invoke() { m_pFunc(); }

 virtual bool Compare(IDelegateVoid* pDelegate);

private:

 PFunc m_pFunc;

Вы читаете Делегаты на C++
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×