Мне нужно зарегистрировать таблицу указателей функций с некоторым API. Скажем, API выглядит следующим образом:Использование класса друга для скрытия частных статических методов обратного вызова
void (*FuncPtr)(void*);
void RegisterCallbacks(FuncPtr const (&callbacks)[10], void* context);
Поскольку я пишу код объектно-ориентированного программирования, создать статические «стуком» методы в моем классе, что в методах очередь вызовов на объект моего класса. Я использую указатель context
, чтобы передать указатель на мой объект. Я хочу статически выделить всю таблицу указателей обратного вызова при статическом времени инициализации. Так что я в конечном итоге с этим:
class MyClass
{
public:
static void Thunk (void* context)
{
reinterpret_cast<MyClass*>(context)->Method();
}
void Method();
//
// More callback thunks and methods...
//
MyClass()
{
RegisterCallbacks(s_callbackTable, this);
}
private:
static const FuncPtr s_callbackTable[];
}
//
// In the .cpp file:
//
const FuncPtr MyClass::s_callbackTable[] =
{
&MyClass::Thunk,
...
};
Проблема с этим подходом является то, что мне нужно сделать MyClass::Thunk
публично видимым, так что статическая инициализация может получить доступ к нему.
Редактировать: Я ошибся. По-видимому, вам не нужно публиковать это.
Я бы предпочел не, хотя. Я могу думать о двух способах решения этой проблемы.
Какой подход лучше?
Создать частный статический метод, и сделать таблицу CallBack статической переменной внутри метода. Таким образом, я могу инициализировать его с помощью указателей на частные методы. Вызовите частный статический метод изнутри конструктора, чтобы получить таблицу.
Создайте отдельный класс, содержащий общедоступные статические методы thunk и сделайте этот класс другом
MyClass
. Вперед объявите этот класс в заголовке дляMyClass
, чтобы разрешить объявление друга. Мне это нравится, потому что он также полностью скрывает методы thunk от любых внешних потребителей. Не совсем уверен, есть ли для этого ощутимая польза.Как так:
// .h file: class MyClassInternals class MyClass { public: void Method(); private: friend class MyClassInternals; static const FuncPtr s_callbackTable[]; } // .cpp file: class MyClassInternals { public: static void Thunk(void* context) { reinterpret_cast<MyClass*>(context)->Method(); } } const FuncPtr MyClass::s_callbackTable[] = { &MyClassInternals::Thunk, ... };
Методы даже не должны быть общедоступными.Структура 'trampolines', благодаря тому, что она определена в рамках« MyClass », наследует ту же семантику, что и внутренний класс, то есть она может обращаться к приватным методам содержащего класса. См. Http://ideone.com/Ai7WW7. Также см. Http://stackoverflow.com/a/5714720/179895, который делает то же предложение, что и вы. – TripShock
@TripShock: Спасибо за разъяснение. Я не большой сторонник 'private' /' protected' и не знал об этой тонкости локальных классов внутри области конструктора/метода. Исправлена. – 6502