class Deletor { public: virtual ~Deletor() {} }; template<typename T> class Base: public Deletor { public: int Run() { return static_cast<T*>(this)->DoIt(); } }; class Derived1: public Base<Derived1> { public: int DoIt() { /* implementation for Derived1 */ } }; class Derived2 : public Base<Derived2> { public: int DoIt() { /* implementation for Derived2 */ } }; int main() { Derived1 Obj1; Derived2 Obj2; Obj1.Run(); /* runs DoIt() implementation */ Obj2.Run(); /* runs DoIt() implementation */ };
int siRun(int&)
. We create the base class RunnableInterface
with the static template function Run_T
and the virtual destructor.Run_T(...)
has the same return type and the same input parameters as siRun(..)
, plus one additional parameter at the beginning, which is a pointer to the object that the static template function works with. Thus, we declare a private variable *m_pfnRun_T
, which is a function pointer, a constructor initializing this pointer to zero, a template function ( Init
) to set the pointer value to the correct implementation of a static function ( &Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.
testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
&Run_T) (siRun
) .
class RunnableInterface { private: int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k) { return static_cast<T*>(pObj)->siRun( k ); } protected: template<typename T> void Init() { m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} int siRun(int &k) { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this, k); } virtual ~RunnableInterface() {} };
, *m_pfnRun_T
. void* const pObj
, RunnableInterface
, .
, , "" (, siRun()
), static_cast
, , , . , SFINAE ( substitution failure is not an error ), , , ; CreateMemberFunctionChecked
, "" , , , , . CheckMemberFunction
Init()
, . FNNAME
; CheckMemberFunction
,
.
// Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } // This corresponding macro is used to check the existence of the // interface function in the derived class. #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); }
, RunnableInterface
:
class RunnableInterface { private: CreateMemberFunctionChecker(siRun); int (*m_pfnRun_T)(void* const, int&); template<typename T> static int Run_T(void* const pObj, int &k ) { return static_cast<T*>(pObj)->siRun(k); } protected: template<typename T> void Init() { CheckMemberFunction(siRun, int (T::*)(int&)); m_pfnRun_T = &Run_T<T>; } public: RunnableInterface(): m_pfnRun_T(0) {} virtual ~RunnableInterface() {} int siRun(int &k) { assert(m_pfnRun_T); return (*m_pfnRun_T)(this, k); } };
, int siRun(int &k)
. , - Init(); int Derived::siRun(int &k)
( Run_T
), :
class Test: public RunnableInterface { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*2; return 0; } protected: int m_value; public: Test(int value): m_value(value) { RunnableInterface::Init<Test>(); } }; class AdjustmentTest: public Test { friend class RunnableInterface; private: int siRun(int &k) { k = m_value*3; return 0; } public: AdjustmentTest(int value): Test(value) { RunnableInterface::Init<AdjustmentTest>(); } };
friend class RunnableInterface;
, RunnableInterface
private
protected
.
TestInterface*
( CRTP), :
int main() { RunnableInterface* const pObj1 = new Test(1); RunnableInterface* const pObj2 = new AdjustmentTest(4); std::list<RunnableInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); std::list<RunnableInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++ ) { RunnableInterface* const p = *i; int k; const int j = p->siRun(k); std::cout << "RUN: " << j << ":" << k << std::endl << std::endl; delete p; } return 0; }
- RunnableInterface
? , - , . , . , , , . Windows, GetModuleHandle()
, . . , Windows :
class TestInterface { private: template <typename T> static int Run_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siRun(k); } typedef void (*PFN_RUN_T)(void* const, int&); CreateMemberFunctionChecker(siRun); // Offset to static template member functions. unsigned long m_ulRun_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, void (T::*)(int&)); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0) {} void siRun(int &k) { assert(m_ulRun_T_Offset); // Make sure Init() was called. char* const pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); (*pfnRun_T)(this, k); } virtual ~TestInterface() {} };
1, 2 3 , : .
Qt Creator 5.0.2 MinGW 4.7 x86 Windows XP Windows 7 x64.

testiface.h ( 1) TestInterface, :
int siRun(); void siReset(int &k); void siSayHello();
1 - testiface.h
#ifndef TESTIFACE_H #define TESTIFACE_H #include <windows.h> // for GetModuleHandle() // Using the SFINAE (Substitution Failure Is Not An Error) technique, // the following macro creates a template class with typename T and a // static boolean member "value" that is set to true if the specified // member function exists in the T class. // This macro was created based on information that was retrieved from // the following URLs: // https://groups.google.com/forum/?fromgroups#!topic/comp.lang.c++/DAq3H8Ph_1k // http://objectmix.com/c/779528-call-member-function-only-if-exists-vc-9-a.html #define CreateMemberFunctionChecker(FNNAME) template<typename T> struct has_member_##FNNAME; template<typename R, typename C> class has_member_##FNNAME<RC::*> { private: template<RC::*> struct helper; template<typename T> static char check(helper<&T::FNNAME>*); template<typename T> static char (& check(...))[2]; public: static const bool value = (sizeof(check<C>(0)) == sizeof(char)); } #define CheckMemberFunction(FNNAME, FNPROTOTYPE) { assert(has_member_##FNNAME<FNPROTOTYPE>::value); } typedef int (*PFN_RUN_T)(void* const); typedef void (*PFN_RESET_T)(void* const, int&); typedef void (*PFN_SAYHELLO_T)(void* const); #ifndef SINGLE_PROCESS class TestInterface { private: // Implement template functions. template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); // Offsets to static template member functions. unsigned long m_ulRun_T_Offset, m_ulReset_T_Offset, m_ulSayHello_T_Offset; protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); char *pBaseOffset = (char*)GetModuleHandle(NULL); m_ulRun_T_Offset = (unsigned long)&Run_T<T> - (unsigned long)pBaseOffset; m_ulReset_T_Offset = (unsigned long)&Reset_T<T> - (unsigned long)pBaseOffset; m_ulSayHello_T_Offset = (unsigned long)&SayHello_T<T> - (unsigned long)pBaseOffset; } public: TestInterface(): m_ulRun_T_Offset(0), m_ulReset_T_Offset(0), m_ulSayHello_T_Offset(0) {} int siRun() { assert(m_ulRun_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RUN_T pfnRun_T = (PFN_RUN_T)(pBaseOffset + m_ulRun_T_Offset); return (*pfnRun_T)(this); } void siReset(int &k) { assert(m_ulReset_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_RESET_T pfnReset_T = (PFN_RESET_T)(pBaseOffset + m_ulReset_T_Offset); (*pfnReset_T)(this, k); } void siSayHello() { assert(m_ulSayHello_T_Offset); // Make sure Init() was called. char *pBaseOffset = (char*)GetModuleHandle(NULL); PFN_SAYHELLO_T pfnSayHello_T = (PFN_SAYHELLO_T)(pBaseOffset + m_ulSayHello_T_Offset); (*pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #else class TestInterface { private: template <typename T> static int Run_T(void* const pObj) { return static_cast<T*>(pObj)->siRun(); } template <typename T> static void Reset_T(void* const pObj, int &k) { static_cast<T*>(pObj)->siReset(k); } template <typename T> static void SayHello_T(void* const pObj) { static_cast<T*>(pObj)->siSayHello(); } // Pointers to static template member functions. PFN_RUN_T m_pfnRun_T; PFN_RESET_T m_pfnReset_T; PFN_SAYHELLO_T m_pfnSayHello_T; CreateMemberFunctionChecker(siRun); CreateMemberFunctionChecker(siReset); CreateMemberFunctionChecker(siSayHello); protected: template <typename T> void Init() { CheckMemberFunction(siRun, int (T::*)()); CheckMemberFunction(siReset, void (T::*)(int&)); CheckMemberFunction(siSayHello, void (T::*)()); m_pfnRun_T = &Run_T<T>; m_pfnReset_T = &Reset_T<T>; m_pfnSayHello_T = &SayHello_T<T>; } public: TestInterface(): m_pfnRun_T(0), m_pfnReset_T(0), m_pfnSayHello_T(0) {} int siRun() { assert(m_pfnRun_T); // Make sure Init() was called. return (*m_pfnRun_T)(this); } void siReset(int &k) { assert(m_pfnReset_T); // Make sure Init() was called. (*m_pfnReset_T)(this, k); } void siSayHello() { assert(m_pfnSayHello_T); // Make sure Init() was called. (*m_pfnSayHello_T)(this); } virtual ~TestInterface() {} }; #endif // SINGLE_PROCESS #endif // TESTIFACE_H
testclasses.h 2 Base
( TestInterface
), DerivedOnce
( Base
) DerivedTwice
( DerivedOnce
). TestInterface::Init(),
- . , , TestInterface()
. TestInterface
siRun, siReset, siSayHello
, private/protected
.
2 - testclasses.h
#ifndef TESTCLASSES_H #define TESTCLASSES_H #ifndef TESTIFACE_H #include "testiface.h" #endif class Base: public TestInterface { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*10; } void siSayHello() { std::cout << "Hello from Base" << std::endl; } protected: int m_value; public: Base(int value = 1): m_value(value) { TestInterface::Init<Base>(); } }; class DerivedOnce: public Base { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*100; } void siSayHello() { std::cout << "Hello from DerivedOnce" << std::endl; } public: DerivedOnce(): Base() { TestInterface::Init<DerivedOnce>(); ++m_value; } }; class DerivedTwice: public DerivedOnce { friend class TestInterface; private: int siRun() { return m_value; } void siReset(int &k) { k = m_value*1000; } void siSayHello() { std::cout << "Hello from DerivedTwice" << std::endl; } public: DerivedTwice(): DerivedOnce() { TestInterface::Init<DerivedTwice>(); ++m_value; } }; #endif // TESTCLASSES_H
main.cpp 3 WinAPI :
Base, DerivedOnce, DerivedTwice
(owner) (client)
, TestInterface*
, siRun, siReset, siSayHello
. ; "OWNER" ( , ) ; ; "CLIENT" ( , .. ), , .
, DerivedTwice::siSayHello()
, . (- CheckMemberFunction(siSayHello, void (T::*)()) TestInterface::Init()):
Assertion failed! Expression: has_member_siSayHello<void (T::*)()>::value
siSayHello
DerivedTwice
, - (, double d
), . (- TestInterface::Init() DerivedTwice
):
In instantiation of 'static void TestInterface::SayHello_T(void*) [with T = DerivedTwide]'; Required from 'void TestInterface::Init [with T = DerivedTwice]
3 - main.cpp
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <list> #include <iostream> #include <conio.h> #include <assert.h> #include "testclasses.h" int main() { const SIZE_T BufSize = 1024; const TCHAR szName[] = TEXT("Local\\SharedMemBlockObject"); const HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BufSize, // maximum object size (low-order DWORD) szName ); // name of mapping object if (hMapFile == NULL) { std::cout << "Could not create file mapping object (" << GetLastError() << ").\n" << std::endl; return 1; } const bool fFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); // Map the file to this process' address space. const LPCTSTR pBuf = (LPTSTR) MapViewOfFile( hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, BufSize ); if (pBuf == NULL) { std::cout << "Could not map view of file (" << GetLastError() << ").\n" << std::endl; CloseHandle( hMapFile ); return 1; } Base *pObj1; DerivedOnce *pObj2; DerivedTwice *pObj3; char *pBuf1 = (char*)pBuf; if (fFirstProcess) { std::cout << "OWNER PROCESS: " << std::endl; // Create TestInterface objects in shared memory. pObj1 = new(pBuf1)Base; // first available memory addr pBuf1 += sizeof(Base); // skip to next available memory addr pObj2 = new(pBuf1)DerivedOnce; pBuf1 += sizeof(DerivedOnce); // skip to next available memory addr pObj3 = new(pBuf1)DerivedTwice; } else { std::cout << "CLIENT PROCESS: " << std::endl; // Access objects that are in shared memory. pObj1 = (Base*)pBuf1; // addr where Base obj was created pBuf1 += sizeof(Base); pObj2 = (DerivedOnce*)pBuf1; // addr where DerivedOnce obj was created pBuf1 += sizeof(DerivedOnce); pObj3 = (DerivedTwice*)pBuf1; // addr where DerivedTwice obj was created } char szHexBuf[12]; sprintf(szHexBuf, "0x%lx", (unsigned long) pBuf); std::cout << "pBuf: " << szHexBuf << std::endl << std::endl; // Place TestInterface* objects in a list. std::list<TestInterface*> list1; list1.insert(list1.end(), pObj1); list1.insert(list1.end(), pObj2); list1.insert(list1.end(), pObj3); // Let TestInterface objects greet, run and reset generically. std::list<TestInterface*>::iterator i; for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; p->siSayHello(); std::cout << "RUN: " << p->siRun() << std::endl; int kk; p->siReset( kk ); std::cout << "RESET: " << kk << std::endl << std::endl; } std::cout << "Press any key to end program" << std::endl; if (fFirstProcess) std::cout << " and destroy objects in shared memory" << std::endl; std::cout << "..." << std::endl; while (!kbhit()) Sleep(100); if (fFirstProcess) { // Objects are no longer needed, call destructors. for (i = list1.begin(); i != list1.end(); i++) { TestInterface* const p = *i; // We need to call the destructor explicitly because // the new with placement operator was used. // We cannot call "delete p;" p->~TestInterface(); } } UnmapViewOfFile(pBuf); CloseHandle(hMapFile); return 0; }
, , , . . .
Source: https://habr.com/ru/post/182824/
All Articles