#include <iostream>
#include <string>
#include <vector>
#include <cstdarg>
using namespace std;
//taka klasa zupelnie abstrakcyjna, potrzebna tylko do polaczenia typow
class CCallback_Base
{
protected:
//mozna powiedziec, ze cala klasa jest dla szpicu
public:
//ale sprobujcie ja wyrzucic :P
};
//maly singleton do tworzenia id dla kolejnych callbackow
class CCallbackIdCreator
{
private:
unsigned int m_dLastId;
public:
CCallbackIdCreator()
{
m_dLastId = 0;
}
static CCallbackIdCreator& inst()
{
static CCallbackIdCreator m_inst;
return m_inst;
}
private:
unsigned int getId()
{
return ++m_dLastId;
}
template <class> friend class Func;
};
//funkcja/metoda (wskaznik)
template <typename T> class Func
{
private:
//metody w klasie
void(T::*m_Method)(void*);
int(T::*m_MethodInt)(void*);
void(CCallback_Base::*m_pMethod)(void*);
int(CCallback_Base::*m_pMethodInt)(void*);
T* m_pClassInst;
//funkcje globalne
void* m_pThis;
void(*m_pFunc)(void*);
int(*m_pFuncInt)(void*);
void* m_pParameter;
//info o tym czego uzywamy w tej instancji tej klasy
int m_bIsInstantiated;
int m_bIsClass;
int m_bIsInt;
//id
unsigned int m_id;
//typy pomocnicze
typedef void (CCallback_Base::*MethodType)(void*);
typedef void (T::*MethodType_T)(void*);
typedef int (CCallback_Base::*MethodType_Int)(void*);
typedef int (T::*MethodType_T_Int)(void*);
public:
//ten konstruktor tylko zeruje wszystko
Func()
{
m_pThis = NULL;
m_pFunc = NULL;
m_pFuncInt = NULL;
m_pParameter = NULL;
m_pClassInst = NULL;
m_Method = NULL;
m_MethodInt = NULL;
m_bIsInstantiated = false;
m_bIsClass = false;
m_bIsInt = false;
m_id = 0;
}
//konstruktor dla metod
Func( T* class_inst, int isInt, ... )
{
va_list list;
m_pClassInst = class_inst;
va_start( list, isInt );
if( isInt )
m_pMethodInt = (MethodType_Int) va_arg( list, MethodType_Int );
else
m_pMethod = va_arg( list, MethodType );
m_pParameter = va_arg( list, void* );
va_end( list );
va_start( list, isInt );
if( isInt )
m_MethodInt = va_arg( list, MethodType_T_Int );
else
m_Method = va_arg( list, MethodType_T );
va_end( list );
m_bIsInstantiated = true;
m_bIsClass = true;
m_bIsInt = isInt;
m_id = CCallbackIdCreator::inst().getId();
}
//konstruktory dla funkcji
Func( void* This, void(*func)(void*), void* par )
{
m_pThis = This;
m_pFunc = func;
m_pParameter = par;
m_bIsInstantiated = true;
m_bIsClass = false;
m_bIsInt = false;
m_id = CCallbackIdCreator::inst().getId();
}
Func( void* This, int(*func)(void*), void* par )
{
m_pThis = This;
m_pFuncInt = func;
m_pParameter = par;
m_bIsInstantiated = true;
m_bIsClass = false;
m_bIsInt = true;
m_id = CCallbackIdCreator::inst().getId();
}
private:
void SetId( unsigned int id )
{
m_id = id;
}
void SetClassInst( CCallback_Base* class_inst )
{
m_pClassInst = (T*) class_inst;
}
CCallback_Base* GetClassInst()
{
return (CCallback_Base*)m_pClassInst;
}
void SetMethod( void(CCallback_Base::*Method)(void*) )
{
m_pMethod = Method;
m_bIsInstantiated = true;
m_bIsClass = true;
m_bIsInt = false;
}
MethodType GetMethod()
{
return m_pMethod;
}
void SetFunc( void* This, void(*func)(void*), void* par )
{
m_pThis = This;
m_pFunc = func;
m_pParameter = par;
m_bIsInstantiated = true;
m_bIsClass = false;
m_bIsInt = false;
}
void SetFunc( void* This, int(*func)(void*), void* par )
{
m_pThis = This;
m_pFuncInt = func;
m_pParameter = par;
m_bIsInstantiated = true;
m_bIsClass = false;
m_bIsInt = true;
}
void Call( void* par = NULL )
{
if( par != NULL )
m_pParameter = par;
if( m_bIsInstantiated )
if( m_bIsClass )
{
(m_pClassInst->*m_pMethod)( m_pParameter );
}
else
{
//assembler potrzebny, aby uwzglednic 'this' danej funkcji
void* pFunc = (void*) m_pFunc;
void* pParameter = (void*) m_pParameter;
//jakby co to zawsze wrzucamy parametr na stos, chocby mial byc = 0
__asm
{
mov ecx,[m_pThis]; //ustawiamy parametr This dla funkcji (zeby wiedziala skad dziala)
push pParameter; //wrzucamy parametr na stos
call [pFunc]; //wywolujemy funkcje
add sp, 4; //czyszczenie stosu (parametrow)
}
}
}
int CallInt( void* par = NULL )
{
if( par != NULL )
m_pParameter = par;
if( m_bIsInstantiated )
if( m_bIsClass )
{
(m_pClassInst->*m_pMethodInt)( m_pParameter );
}
else
{
//assembler potrzebny, aby uwzglednic 'this' danej funkcji
void* pFunc = (void*) m_pFuncInt;
void* pParameter = (void*) m_pParameter;
//jakby co to zawsze wrzucamy parametr na stos, chocby mial byc = 0
__asm
{
mov ecx,[m_pThis]; //ustawiamy parametr This dla funkcji (zeby wiedziala skad dziala)
push pParameter; //wrzucamy parametr na stos
call [pFunc]; //wywolujemy funkcje
add sp, 4; //czyszczenie stosu (parameter)
}
}
//aby kompilator sie nie plul w zasadzie :P
return true;
}
public:
void operator=( const Func<T>& obj )
{
m_pThis = obj.m_pThis;
m_pFunc = obj.m_pFunc;
m_pFuncInt = obj.m_pFuncInt;
m_pParameter = obj.m_pParameter;
m_pClassInst = obj.m_pClassInst;
m_Method = obj.m_Method;
m_MethodInt = obj.m_MethodInt;
m_bIsInstantiated = obj.m_bIsInstantiated;
m_bIsClass = obj.m_bIsClass;
m_bIsInt = obj.m_bIsInt;
m_id = obj.m_id;
}
bool operator==( const Func<T>& obj ) const
{
if( m_id == obj.m_id )
return true;
else
return false;
}
bool operator!=( const Func<T>& obj ) const
{
if( m_id != obj.m_id )
return true;
else
return false;
}
friend class Callback;
};
//container (handler)
class Callback
{
private:
Func<CCallback_Base> m_callback;
public:
//konstruktory ogolne
Callback()
{
}
Callback( const Callback& obj )
{
m_callback = obj.m_callback;
}
//destruktor dla niektorych kompilatorow bez wyobrazni
~Callback()
{
}
//konstruktor dla metod
template <typename T> Callback( Func<T> method )
{
m_callback.SetClassInst( method.GetClassInst() );
m_callback.SetMethod( method.GetMethod() );
}
//konstruktory dla funkcji
Callback( void* This, void(*func)(void*), void* par )
{
m_callback.SetFunc( This, func, par );
}
Callback( void* This, int(*func)(void*), void* par )
{
m_callback.SetFunc( This, func, par );
}
//wywolanie metody/funkcji
void call( void* par = NULL )
{
m_callback.Call( par );
}
//wywolanie metody/funkcji ze zwrotem parametru
int callInt( void* par = NULL )
{
return m_callback.CallInt( par );
}
void operator= ( const Callback& obj )
{
m_callback = obj.m_callback;
}
bool operator==( const Callback& obj ) const
{
if( m_callback.m_id == obj.m_callback.m_id )
return true;
else
return false;
}
bool operator!=( const Callback& obj ) const
{
if( m_callback.m_id != obj.m_callback.m_id )
return true;
else
return false;
}
};
/* test functions */
void some_func3_1( void* );
void some_func3_2( void* );
int some_func3_3( void* );
void some_func( void* );
//test A
void some_func( void* par )
{
cout << "\tcalled some_func" << endl;
if( par != NULL )
cout << "\t\tgot param: " << ((int)par) << endl;
}
//test B
int some_func3_3( void* myInt )
{
int dTmp = (int) myInt;
cout << "\tcalled some_func3_3" << endl << "\t\tgot param: " << dTmp << endl << "\t\tret val: ";
if( dTmp != 4 )
{
cout << "false (par != 4)" << endl;
return false;
}
cout << "true (par == 4)" << endl;
return true;
}
//test C
//global func inside another func
Callback c( &some_func3_1, &some_func3_2, NULL );
void some_func3_2( void* myInt )
{
int dTmp = (int) myInt;
cout << "\tcalled some_func3_2" << endl << "\t\tgot param: " << dTmp << endl;
}
void some_func3_1( void* )
{
int myPrivateInt = 6;
c.call( (void*) myPrivateInt );
}
//test D
class SomeClass
{
public:
SomeClass(){}
~SomeClass(){}
void someMethod( void* par )
{
cout << "\tcalled someMethod" << endl;
if( par != NULL )
cout << "\t\tgot param: " << ((int)par) << endl;
}
};
//test A, B, C, D
int main( int argc, char* argv[] )
{
//class method
SomeClass obj;
Callback d( Func<SomeClass>(&obj, false, &SomeClass::someMethod, 0) );
//global func
Callback a( 0, &some_func, 0 );
Callback b( 0, &some_func3_3, (void*)4 );
//calling
cout << "void:" << endl;
a.call();
a.call( (void*) 123 );
d.call();
d.call( (void*) 5 );
some_func3_1( 0 );
cout << endl << "int: " << endl;
b.callInt();
getchar();
return 0;
}