Как делегаты в C # лучше, чем указатели на функции в C / C ++? - PullRequest
14 голосов
/ 29 марта 2010

Делегаты в C # предлагают функциональность, аналогичную указателям на функции в C. Я слышал, как кто-то говорил: «Делегаты C # на самом деле лучше, чем указатели на функции в C». Как так? Пожалуйста, объясните на примере.

Ответы [ 4 ]

15 голосов
/ 29 марта 2010

«Лучше» субъективно - но основные различия:

  • Тип безопасности. Делегату гарантируется не только ссылка на действительный метод, но и метод с правильной подписью.
  • Это указатель на метод bound - то есть делегат может указывать на конкретный объект, для которого вызывается делегат. Таким образом, делегат Action<string> может ссылаться на alice.GetName или bob.GetName, а не на Person.GetName. Это может быть похожим на C ++ "указатель на член" - я не уверен.

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

РЕДАКТИРОВАТЬ: Как отмечает CWF в комментариях, еще одно возможное преимущество делегатов C # заключается в том, что декларации типов делегатов легче для чтения многими людьми. Это может быть вопрос знакомства и опыта, конечно.

4 голосов
/ 29 марта 2010

Одна вещь, которую делегат обеспечивает, что указатель на функцию C / C ++ не имеет, это безопасность типов. То есть в C / C ++ вы можете поместить указатель функции в переменную указателя функции, объявленную с неверной сигнатурой функции (или даже с двойным или худшим int с соответствующим коаксиальным выражением), и компилятор будет рад создать код, который вызывает функция совершенно неверно. В C # сигнатура типа функции должна соответствовать сигнатуре типа делегата, а также способу, которым в конечном итоге вызывается делегат.

4 голосов
/ 29 марта 2010

Указатели всегда могут указывать на неправильное место :) Т.е. это может указывать на неработающее или произвольное место в памяти.

Но с точки зрения функциональности указатели функций могут делать все, что могут делать делегаты.

1 голос
/ 20 июля 2010

Многие люди называют делегатов C # более «типобезопасными», чем указатели функций C ++, и я действительно считаю, что это вводит в заблуждение. На самом деле они не более безопасны по типу, чем указатели функций C ++. Пример кода C ++ (скомпилирован в MSVS 2005 SP1):

typedef int (*pfn) (int);

int f (int) {
   return 0;
}

double d (int) {
   return 1;
}

int main()
{
   pfn p=f; // OK
   p=d; // error C2440: '=' : cannot convert from 'double (__cdecl *)(int)' to 'pfn'
   p=(pfn)d;
}

Таким образом, как видно из приведенного выше примера, если не использовать «грязные хаки» для «закрытия» компилятора, несоответствие типов легко обнаруживается и сообщение компилятора легко понять. Так что это безопасность типов, как я понимаю.

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

class A {
public:

   int f (int) {
      return 2;
   }

};

typedef int (A::*pmfn) (int);

int main()
{
   pmfn p=&(A::f);
   // Now call it.
   A *a=new A;
   (a->*p)(0); // Calls A::f
}

Опять же, все совершенно безопасно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...