📜 ⬆️ ⬇️

Polymorphism without virtual functions

This article presents a pattern that can be used to provide dynamic binding without using virtual functions to call overloaded methods for objects of a heterogeneous container when it is traversed.

On the Rights of Introduction


It is usually not recommended to resort to shared objects between processes in C ++, however this is possible. We will understand why this is generally necessary:
  1. In dynamic linking, when a virtual function is called for an object, the compiler does not know which function should be executed. To allow calls to virtual functions, the compiler compiles a table of virtual functions ( vtable ) for each class that declares virtual functions. Vtable contains offsets for these virtual functions. When, during the execution of a program, a class object is created, it is assigned a pointer to a Vtable class. Since this pointer is in the data segment of the process that creates the object, even if the object is created in the shared memory segment, the pointer to the Vtable will be available only for the process that created the object. This means that other processes that will try to call the virtual function of the shared object will fail. This is the main reason for considering alternatives to dynamic linking for sharing objects between processes.
  2. Pointers to objects in C ++ created in shared memory will be available in different processes only if they associate a shared memory segment with the same virtual address, which the OS cannot guarantee (the OS can offer a virtual address and associate the process with this address only if that address is no longer used). The solution is to use offsets for virtual addresses, which, when creating a pointer to an object, are added to the base virtual address. Likewise, instead of pointers in C ++, we must have offsets.
  3. The compiler allocates static data members of the class in the standard process data segment, i.e., different processes will have different copies of these members. Thus, if one copy of these static data members is needed, they must be replaced with offsets by the base virtual address (which is mapped to shared memory).
  4. Simultaneous use of the same shared object by different processes may result in data corruption. To ensure mutual exclusion, mutual IPC ( inter-process communication ) mechanism should be used.

"Curiously Recurring Template Pattern" ( CRTP ) is the most commonly used alternative to dynamic linking. CRTP is used to implement static polymorphism. Static polymorphism achieves a similar effect due to virtual functions, allowing you to select overloaded methods in derived classes at the compilation stage, rather than at run time. Using CRTP, the Derived class inherits the Base base template class that implements the Derived class interface. To properly remove instances of a derived class, Base inherits the Deletor class, which defines a virtual destructor. Virtual destructor provides objects of derived classes through a pointer to the base class.
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 */ }; 

Without using a base class of type Deletor, as in the example above, derived classes cannot be stored heterogeneously (for example, in a container), because each CRTP base class is a unique type. Base and Base are unrelated classes, so even though these objects can be stored heterogeneously in the BaseDeletor * container of objects, it will not be possible to provide polymorphism with iterations (by calling, for example, the DoIt () method, as in the example). CRTP is suitable for applications where clients need to create only one type of derived class.

Simulated interface (design pattern)


The pattern presented here uses templates of static member functions, rather than template classes. This pattern requires the creation of a base class that defines patterns of static functions that will have access to the interface functions of derived classes. The goal is to add objects of derived classes to the container and then, when passing the container, it would be possible to call interface functions without having to know anything about the type of the object.
')
Suppose that we need a class hierarchy with a dynamically related method 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; }

, , , . . .
  1. &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; }

    , , , . . .
  2. &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