Другим сценарием является то, что вы нанесли нулевой объект в тип значения . Например, код ниже:
object o = null;
DateTime d = (DateTime)o;
Он выкинет NullReferenceException
в роли. В приведенном выше примере это кажется совершенно очевидным, но это может произойти в более «поздних связующих» сложных сценариях, где нулевой объект был возвращен из некоторого кода, которого вы не являетесь, и приведение, например, генерируется некоторой автоматической системой.
Одним из примеров этого является этот простой фрагмент привязки ASP.NET с элементом управления календарем:
" />
Здесь SelectedDate
на самом деле является свойством - типа DateTime
- типа Calendar
Web Control, и привязка может отлично вернуть что-то null. Неявный генератор ASP.NET создаст кусок кода, который будет эквивалентен приведенному выше методу. И это поднимет NullReferenceException
, что довольно сложно определить, потому что он лежит в сгенерированном ASP.NET коде, который компилирует отлично ...
Поскольку вы используете C ++, почему бы не сделать обратный вызов объектом functor ? Затем вы можете использовать std::mem_fun
.
Изменить: Кажется, std::mem_fun
устарел в последнем стандарте C ++ 11. Поэтому std::function
может быть лучшим решением, если у вас есть новый компилятор.
См. этот вопрос SO для подсказок об использовании его.
Зависит от того, как вы его используете ... например, Singlton был бы намного проще
struct MyStruct {
static MyStruct& Create() {
static MyStruct m; return m;
}
static int StaticCallBack(std::string str) {
return Create().Callback(str)
}
private:
int CallBack(std::string str);
MyStruct();
};
Или, если вы хотите иметь много из этих объектов, у вас есть несколько вариантов. Вам понадобится способ маршрутизации до вызова callback.
Из-за негибкого жесткого кодирования фактического типа функции для обратного вызова вы не можете использовать какие-либо обычные адаптивные или привязывающие трюки, чтобы помочь вам здесь. Сторонняя библиотека действительно хочет, чтобы вы передали функцию, не являющуюся членом, и вы не можете многое сделать. Вы можете подумать о том, почему вы пытаетесь передать ему адрес функции-члена, и если ваш дизайн или использование библиотеки могут измениться.
Один из вариантов, если вам нужно только установить один обратный вызов, должен иметь частную функцию static или namespace, которая ссылается на указатель экземпляра singleton, и использует это для отправки по обратному вызову.
Если вам нужно несколько элементов, возможно, шаблон будет обернуть хакерство (непроверенный код здесь, просто идея).
template <int which_callback>
struct CallbackHolderHack
{
static int callback_func(std::string str) { dispatchee_->myCallback(str); }
static MyStruct* dispatchee_;
};
template <int which_callback>
MyStruct* CallbackHolderHack::dispatchee_(0);
И использовать его:
CallbackHolderHack<0>::dispatchee_ = new MyStruct;
registerCallback(&CallbackHolderHack<0>::callback_func);
class ICallBackInterface
{
public:
virtual void FireCallBack( std::string& str ) = 0;
};
std::set<ICallBackInterface*> CallBackMgr;
class MyStruct : public ICallBackInterface
{
public:
MyStruct()
{
CallBackMgr.insert( this );
}
~MyStruct()
{
CallBackMgr.erase( this );
}
virtual void FireCallBack( std::string& str )
{
std::cout << "MyStruct called\n";
}
};
void FireAllCallBack(std::string& str )
{
for ( std::set<ICallBackInterface*>::iterator iter = CallBackMgr.begin();
iter != CallBackMgr.end();
++iter)
{
(*iter)->FireCallBack( str );
}
}
Это еще один способ использования полиморфизма для достижения такого же эффекта
Вы пытаетесь передать указатель функции-члена как обычный указатель функции, который не будет работать. Функции-члены должны иметь указатель this
как один из скрытых параметров, что не относится к нормальным функциям, поэтому их типы несовместимы.
Вы можете:
static
) std::string
и использует что-то вроде boost bind
для связывания первых двух аргументов std::function
(я думаю, что это имя)