はじめに
通常、C ++のプロセス間で共有オブジェクトに頼ることは推奨されませんが、これは可能です。 なぜこれが必要なのかを考えてみましょう。
- 動的バインディングでは、オブジェクトに対して仮想関数が呼び出されると、コンパイラはどの関数を実行する必要があるかを知りません。 仮想関数呼び出しを解決するために、コンパイラーは、仮想関数を宣言するクラスごとに仮想関数テーブル ( vtable )をコンパイルします。 Vtableには、これらの仮想関数のオフセットが含まれています。 実行時に、クラスオブジェクトが作成されると、クラスのVtableへのポインターが割り当てられます。 なぜなら このポインターは、オブジェクトを作成するプロセスのデータセグメントにあり、オブジェクトが共有メモリセグメントに作成された場合でも、Vtableへのポインターは、オブジェクトを作成したプロセスでのみ使用できます。 これは、共有オブジェクトの仮想関数を呼び出そうとする他のプロセスが失敗することを意味します。 これが、プロセス間でオブジェクトを共有するための動的リンクの代替案を検討する主な理由です。
- 共有メモリに作成されたC ++のオブジェクトへのポインタは、OSが保証できない同じ仮想アドレスに共有メモリセグメントを関連付ける場合にのみ、異なるプロセスで使用可能になります(OSは仮想アドレスを提供し、プロセスをこれに関連付けることができます)そのアドレスが使用されなくなった場合にのみアドレス)。 解決策は、オブジェクトへのポインターを作成するときにベース仮想アドレスに追加される仮想アドレスにオフセットを使用することです。 同様に、C ++のポインターの代わりに、オフセットが必要です。
- コンパイラは、クラスの静的データメンバーをプロセスデータの標準セグメントに割り当てます。つまり、プロセスごとにこれらのメンバーのコピーが異なります。 したがって、これらの静的データメンバのコピーが1つ必要な場合は、基になる仮想アドレス(共有メモリにマップされる)へのオフセットで置き換える必要があります。
- 1つの共有オブジェクトの異なるプロセスで同時に使用すると、データが破損する可能性があります。 相互排除を保証するには、 IPC ( プロセス間通信 )メカニズムを使用する必要があります
不思議な繰り返しテンプレートパターン( CRTP )は、ダイナミックリンクの最も一般的に使用される代替です。 CRTPは、静的ポリモーフィズムを実装するために使用されます。 静的ポリモーフィズムは、仮想関数のおかげで同様の効果を達成し、実行時ではなくコンパイル時に派生クラスでオーバーロードされたメソッドを選択できます。 CRTPを使用して、Derivedクラスは、Derivedクラスインターフェイスを実装するBaseテンプレートクラスを継承します。 派生クラスのインスタンスを適切に削除するために、Baseは仮想デストラクタを定義するDeletorクラスを継承します。 仮想デストラクタは、基本クラスへのポインタを通じて派生クラスのオブジェクトを提供します。
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 */ };
上記の例のようにDeletor型の基本クラスを使用しないと、CRTPの各基本クラスは一意の型であるため、派生クラスを異種(コンテナなど)に格納できません。 BaseとBaseは関連するクラスではないため、これらのオブジェクトはオブジェクトのBaseDeletor *コンテナーに異種混合で格納できますが、反復を使用してポリモーフィズムを提供することはできません(例のようにDoIt()メソッドを呼び出します)。 CRTPは、クライアントが派生クラスを1種類のみ作成する必要があるアプリケーションに適しています。
シミュレートされたインターフェイス(デザインパターン)
ここで紹介するパターンは、テンプレートクラスではなく、静的メンバー関数のテンプレートを使用します。 このパターンでは、派生クラスのインターフェイス関数にアクセスする静的関数のパターンを定義する基本クラスを作成する必要があります。 目標は、派生クラスのオブジェクトをコンテナに追加することです。コンテナが通過すると、オブジェクトの種類について何も知らなくてもインターフェイス関数を呼び出すことができます。
動的にリンクされた
int siRun(int&)
メソッドを持つクラス階層が必要だとします。 静的テンプレート関数
Run_T
と仮想デストラクタを使用して、基本クラス
RunnableInterface
を作成します。
Run_T(...)
は、
siRun(..)
と同じ戻り値型と同じ入力パラメーターに加えて、先頭に1つの追加パラメーターがあります。これは、静的テンプレート関数が機能するオブジェクトへのポインターです。 したがって、プライベート変数
*m_pfnRun_T
を宣言します。これは、関数へのポインター、このポインターをゼロに初期化するコンストラクター、ポインターの値を静的関数(
&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; }
, , , . . .
の正しい実装に設定するテンプレート関数(
Init
&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 2Base
(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 2Base
(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 2Base
(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 2Base
(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 2Base
(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; }
, , , . . .