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

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

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

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

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

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

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

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

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

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

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

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

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

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