• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 447
  • Last Modified:

C++ pointer to member function

I am sure I am just getting caught up in the syntactic ugliness of function pointers here, but can somebody help me out?

I am getting this compiler error on the following code:
error C2664: 'Derived::Derived(FxnPtr)' : cannot convert parameter 1 from 'void (__thiscall TestApp::* )(void)' to 'FxnPtr'
#define TEST_API __declspec(dllexport)
 
//Base and Derived classes are exported from a DLL
class TEST_API Base
{
public:
	Base() {}
	virtual ~Base() {}
};
 
typedef void(Base::*FxnPtr)();
 
class TEST_API Derived :public Base
{
public:
	Derived(FxnPtr fxn) {}
	~Derived() {}
};
 
//The following code is in the EXE
#include "windows.h"
 
class TestApp :public Derived
{
public:
	TestApp() :Derived(&TestApp::Func) {}
	~TestApp() {}
 
	void Func() {}
};
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	return 0;
}

Open in new window

0
cuziyq
Asked:
cuziyq
  • 2
2 Solutions
 
evilrixSenior Software Engineer (Avast)Commented:
Use the Curiously recurring template pattern to do this.
http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
#define TEST_API __declspec(dllexport)
 
//Base and Derived classes are exported from a DLL
class TEST_API Base
{
public:
	Base() {}
	virtual ~Base() {}
};
 
template <typename T>
class TEST_API Derived :public Base
{
typedef void(T::*FxnPtr)();
 
public:
	Derived(FxnPtr fxn) {}
	~Derived() {}
};
 
//The following code is in the EXE
#include "windows.h"
 
class TestApp :public Derived<TestApp>
{
public:
	TestApp() :Derived<TestApp>(&TestApp::Func) {}
	~TestApp() {}
 
	void Func() {}
};
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	return 0;
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
You can also do this using dynamic polymorphism...

Note what the standard says about this...

"If the dynamic type of the object does not contain the member to which the pointer refers, the behavior is
undefined."

The following are the complete details from the C++ standard regarding member function pointers...

5.5 Pointer-to-member operators

1 The pointer-to-member operators ->* and .* group left-to-right.
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression

2 The binary operator .* binds its second operand, which shall be of type pointer to member of T (where
T is a completely-defined class type) to its first operand, which shall be of class T or of a class of which T
is an unambiguous and accessible base class. The result is an object or a function of the type specified by
the second operand.

3 The binary operator ->* binds its second operand, which shall be of type pointer to member of T (where
T is a completely-defined class type) to its first operand, which shall be of type pointer to T or pointer to
a class of which T is an unambiguous and accessible base class. The result is an object or a function of the
type specified by the second operand.

4 If the dynamic type of the object does not contain the member to which the pointer refers, the behavior is
undefined.

5 The restrictions on cv-qualification, and the manner in which the cv-qualifiers of the operands are combined
to produce the cv-qualifiers of the result, are the same as the rules for E1.E2 given in 5.2.5. [Note: it is not
possible to use a pointer to member that refers to a mutable member to modify a const class object.

For example,
struct S {
mutable int i;
};
const S cs;
int S::* pm = &S::i; // pm refers to mutable member S::i
cs.*pm = 88; // ill-formed: cs is a const object
]

6 If the result of .* or ->* is a function, then that result can be used only as the operand for the function
call operator (). [Example:
(ptr_to_obj->*ptr_to_mfct)(10);
calls the member function denoted by ptr_to_mfct for the object pointed to by ptr_to_obj. ] The
result of a .* expression is an lvalue only if its first operand is an lvalue and its second operand is a
pointer to data member. The result of an ->* expression is an lvalue only if its second operand is a pointer
to data member. If the second operand is the null pointer to member value (4.11), the behavior is undefined.
#include <iostream>
 
#define TEST_API __declspec(dllexport)
 
//Base and Derived classes are exported from a DLL
class TEST_API Base
{
public:
	Base() {}
	virtual ~Base() {}
	virtual void Func()
	{
		std::cout << "Unexpected" << std::endl;
	}
};
 
typedef void(Base::*FxnPtr)();
 
class TEST_API Derived :public Base
{
public:
	Derived(FxnPtr fxn):m_fxn(fxn){}
	~Derived() {}
 
	FxnPtr m_fxn;
 
	void doit()
	{
		(this->*m_fxn)();
	}
};
 
//The following code is in the EXE
#include "windows.h"
 
class TestApp :public Derived
{
public:
	TestApp() :Derived((FxnPtr)&TestApp::Func) {}
	~TestApp() {}
 
	void Func()
	{
		std::cout << "Expected" << std::endl;
	}
};
 
int main()
{
	TestApp t;
	t.doit();
}

Open in new window

0
 
DanRollinsCommented:
Depending on your specific needs, there might be other ways to solve your problem.  Are you needing to pass the address of an object member function to a Windows API fn (such as SetTimer) that needs a callback address?
0

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now