Вызов указателя функции C ++ на конкретный экземпляр объекта

Если вы хотите получить значения всех констант определенного типа, из целевого типа, это метод расширения (расширение некоторых ответов на этой странице):

public static class TypeUtilities
{
    public static List<T> GetAllPublicConstantValues<T>(this Type type)
    {
        return type
            .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
            .Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(T))
            .Select(x => (T)x.GetRawConstantValue())
            .ToList();
    }
}

Тогда для такого класса

static class MyFruitKeys
{
    public const string Apple = "apple";
    public const string Plum = "plum";
    public const string Peach = "peach";
    public const int WillNotBeIncluded = -1;
}

Вы можете получить константные значения string следующим образом:

List<string> result = typeof(MyFruitKeys).GetAllPublicConstantValues<string>();
//result[0] == "apple"
//result[1] == "plum"
//result[2] == "peach"
13
задан fryguybob 30 September 2008 в 02:25
поделиться

10 ответов

Я настоятельно рекомендую превосходную библиотеку FastDelegate Don Clugston. Это обеспечивает все вещи, которые Вы ожидали бы настоящего делегата и компилируете вниз в несколько инструкций ASM в большинстве случаев. Сопроводительная статья является хорошим чтением на указателях функции членства также.

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

9
ответ дан Ron Warholic 30 September 2008 в 02:25
поделиться

Убежавший от необработанных указателей функции C++ и использования std::function вместо этого.

можно использовать boost::function при использовании старого компилятора, такого как Visual Studio 2008, который не имеет никакой поддержки C++ 11.
boost:function и std::function то же самое - они вытянули довольно мало материала повышения в библиотеку станд. для C++ 11.

Примечание: можно хотеть прочитать документацию функции повышения вместо Microsoft один, поскольку легче понять

11
ответ дан Orion Edwards 30 September 2008 в 02:25
поделиться

Вы упоминаете, что повышение не является опцией для Вас, но Вы имеете TR1 доступный Вам?

функция предложений TR1, свяжите, и объекты mem_fn на основе библиотеки повышения, и можно было уже связать его компилятором. Это еще не стандартно, но по крайней мере два компилятора, которые я использовал недавно, имели его.

http://en.wikipedia.org/wiki/Technical_Report_1
http://msdn.microsoft.com/en-us/library/bb982702.aspx

1
ответ дан Corey Ross 30 September 2008 в 02:25
поделиться

Можно использовать указатели функции для индексации в vtable из приведенного примера объекта. Это называют указатель функции членства . Ваш синтаксис должен был бы измениться на использование ".*" и "&::" операторы:

class A;
class B;
typedef void (B::*EventFunction)(int nEvent)

и затем:

class A
{
private:
    EventFunction handler;

public:
    void SetEvent(EventFunction func) { handler = func; }

    void EventOne(B* delegate) { ((*delegate).*handler)(1); } // note: ".*"
};

class B
{
private:
    A a;
public:
    B() { a.SetEvent(&B::EventFromA); } // note: "&::"

    void EventFromA(int nEvent) { /* do stuff */ }
};
11
ответ дан David Citron 30 September 2008 в 02:25
поделиться

У меня есть ряд классов для этой точной вещи, которую я использую в своей платформе C++.

http://code.google.com/p/kgui/source/browse/trunk/kgui.h

, Как я обрабатываю его, является каждой функцией класса, которая может использоваться в качестве потребностей обратного вызова статическая функция, которая связывает тип объекта с ним. У меня есть ряд макросов, которые делают это автоматически. Это делает статическую функцию с тем же именем кроме с "CB _" префикс и дополнительный первый параметр, который является указателем объекта класса.

Контроль Типы классов kGUICallBack и различные шаблонные версии этого для обработки различных комбинаций параметров.

#define CALLBACKGLUE(classname , func) static void CB_ ## func(void *obj) {static_cast< classname *>(obj)->func();}
#define CALLBACKGLUEPTR(classname , func, type) static void CB_ ## func(void *obj,type *name) {static_cast< classname *>(obj)->func(name);}
#define CALLBACKGLUEPTRPTR(classname , func, type,type2) static void CB_ ## func(void *obj,type *name,type2 *name2) {static_cast< classname *>(obj)->func(name,name2);}
#define CALLBACKGLUEPTRPTRPTR(classname , func, type,type2,type3) static void CB_ ## func(void *obj,type *name,type2 *name2,type3 *name3) {static_cast< classname *>(obj)->func(name,name2,name3);}
#define CALLBACKGLUEVAL(classname , func, type) static void CB_ ## func(void *obj,type val) {static_cast< classname *>(obj)->func(val);}
0
ответ дан KPexEA 30 September 2008 в 02:25
поделиться
  • 1
    That' s не строковая оценка. И цикличное выполнение по (некоторое вовлечение выражения $results) очень отличается от цикличного выполнения по ($results). Первый скопирует массив (использующий память); последний исказит к нему (и позволит изменять элементы через переменную цикла). – ysth 1 December 2008 в 03:06

Несколько неясно, что Вы пытаетесь выполнить здесь. то, что ясно, - то, что указатели функции не являются путем.

, возможно, то, что Вы ищете, является указателем на метод.

0
ответ дан shoosh 30 September 2008 в 02:25
поделиться

К сожалению, тип EventFunction не может указать на функцию B, потому что это не корректный тип. Вы могли сделать его корректным типом, но это, вероятно, не действительно решение, которое Вы хотите:

typedef void (*B::EventFunction)(int nEvent);

... и затем все работает, как только Вы называете обратный вызов с obhect B. Но Вы, вероятно, хотите быть в состоянии вызвать функции за пределами B в других классах, которые делают другие вещи. Это - вид точки обратного вызова. Но теперь этот тип указывает на что-то определенно в B. Более прекрасные решения:

  • Делают B базовым классом, затем переопределяют виртуальную функцию друг для друга класс, который можно было бы назвать. Тогда хранит указатель на B вместо указателя функции. Намного более чистый.
  • , Если бы Вы не хотите связывать функцию с определенным типом класса, даже базовый класс (и я не обвинил бы Вас), тогда я предлагаю, чтобы Вы сделали функцию, которая вызвана статическая функция: "static void EventFrom A(int nEvent);". Тогда можно назвать его непосредственно без объекта B. Но Вы, вероятно, хотите, чтобы он назвал определенный экземпляр B (если B не является одиночным элементом).
  • Поэтому, если Вы хотите быть в состоянии назвать определенный экземпляр B, но быть в состоянии назвать non-B's также тогда необходимо передать что-то еще функции обратного вызова так, чтобы функция обратного вызова могла назвать правильный объект. Сделайте свою функцию помехами, как выше, и добавьте пустоту* параметр, который Вы сделаете указателем на B.

На практике Вы видите два решения этой проблемы: специальные системы, куда Вы передаете пустоту* и событие и иерархии с виртуальными функциями в базовом классе, как системы управления окнами

1
ответ дан markets 30 September 2008 в 02:25
поделиться

Если Вы взаимодействуете через интерфейс с библиотекой C, то Вы не можете использовать функцию членства класса, не используя что-то как boost::bind. Библиотеки Most C, которые берут функцию обратного вызова обычно также, позволяют Вам передавать дополнительный аргумент своего выбора (обычно типа void*), который можно использовать для начальной загрузки класса, как так:


class C
{
public:
  int Method1(void) { return 3; }
  int Method2(void) { return x; }

  int x;
};

// This structure will hold a thunk to
struct CCallback
{
  C *obj;  // Instance to callback on
  int (C::*callback)(void);  // Class callback method, taking no arguments and returning int
};

int CBootstrapper(CCallback *pThunk)
{
  // Call the thunk
  return ((pThunk->obj) ->* (pThunk->callback))( /* args go here */ );
}

void DoIt(C *obj, int (C::*callback)(void))
{
  // foobar() is some C library function that takes a function which takes no arguments and returns int, and it also takes a void*, and we can't change it
  struct CCallback thunk = {obj, callback};
  foobar(&CBootstrapper, &thunk);
}

int main(void)
{
  C c;
  DoIt(&c, &C::Method1);  // Essentially calls foobar() with a callback of C::Method1 on c
  DoIt(&c, &C::Method2);  // Ditto for C::Method2
}
2
ответ дан Adam Rosenfield 30 September 2008 в 02:25
поделиться
  • 1
    @ysth - Существует... см. " $results" оценки;. мое предложение должно было использовать call_to_service () пример, данный ранее. Мой ответ был чем-то вроде " язык в щеке solution" к ограничению, введенному плакатом так да его польза для указания на его дефекты. – draegtun 1 December 2008 в 14:41

Можно найти FAQ C++ Marshall Cline полезный для того, что Вы пытаетесь выполнить.

4
ответ дан Victor Sergienko 30 September 2008 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: