C++ Inheritance and Member Function Pointers

C++ inheritance and member function pointers

C++03 std, §4.11 2 Pointer to member conversions:

An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to member of D of type cv T,” it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to the null member pointer value of the destination type. 52)

52)The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.

In short, you can convert a pointer to a member of an accessible, non-virtual base class to a pointer to a member of a derived class as long as the member isn't ambiguous.

class A {
public:
void foo();
};
class B : public A {};
class C {
public:
void bar();
};
class D {
public:
void baz();
};
class E : public A, public B, private C, public virtual D {
public:
typedef void (E::*member)();
};
class F:public E {
public:
void bam();
};
...
int main() {
E::member mbr;
mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
mbr = &C::bar; // invalid: C is private
mbr = &D::baz; // invalid: D is virtual
mbr = &F::bam; // invalid: conversion isn't defined by the standard
...

Conversion in the other direction (via static_cast) is governed by § 5.2.9 9:

An rvalue of type "pointer to member of D of type cv1 T" can be converted to an rvalue of type "pointer to member of B of type cv2 T", where B is a base class (clause 10 class.derived) of D, if a valid standard conversion from "pointer to member of B of type T" to "pointer to member of D of type T" exists (4.11 conv.mem), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.11) The null member pointer value (4.11 conv.mem) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5 expr.mptr.oper.]

11) Function types (including those used in pointer to member function
types) are never cv-qualified; see 8.3.5 dcl.fct.

In short, you can convert from a derived D::* to a base B::* if you can convert from a B::* to a D::*, though you can only use the B::* on objects that are of type D or are descended from D.

Member-function pointers and inheritance

The problem is that the implicitly passed this differs in type. Either you cast it, but that will probably fail in the presence of multiple inheritance. A better & more robust solution would be to change the signature to:

template< typename T >
bool WaitEvent( bool ( T::*predicate )(), int timeout ) { ... }

C++ Pointers to Member Functions Inheritance

If you can use boost libraries, I would suggest you use boost::function for the task at hand.

class A {
public:
void doSomething( boost::function< void ( int ) > callback )
{
callback( 5 );
}
};

Then any inheriting (or external class) can use boost::bind do make a call:

class B {
public:
void my_method( int a );
};
void test()
{
B b;
A a;
a.doSomething( boost::bind( &B::my_method, &b, _1 ) );
};

I have not checked the exact syntax and I have typed it from the top of my head, but that is at least close to the proper code.

C++ member function pointers in class and subclass

After some thought and a redesign i was able to achieve what i wanted. Although i am stubborn and still using inheritance i have reimplemented the map. This is how it works now:

class Location {
// ...

protected:
std::map<std::string, std::function<void(void)>> m_mEvents;
};

And now i can handle it like this:

class CivicCenter : public Location {
public:
CivicCenter() {
// this is done by a macro which lookes better than this
this->m_mEvents["onTriggerSomething"] =
std::bind(&CivicCenter::onTriggerSomething, this);
}

void onTriggerSomething() {
// ...
}

// ...
};

With easy use of std::bind i am able to implement generic function pointers. When using parameters like in std::function<void(int, int)> remeber to use either boost's _1 and _2 or lambda expressions like me:

std::function<void(int,int)> f = [=](int a, int b) {
this->anotherFunctionWithParams(a, b);
};

But this is just pointed out due to completeness of my solution.

cast a pointer to member function in derived class to a pointer to abstract member function

You could shorten this example a lot:

struct B {
virtual void foo() = 0;
};

struct D : B {
void foo() override { }
};

int main() {
void (B::*ptr)() = &D::foo; // error: cannot initialize a variable of
// type 'void (B::*)()' with an rvalue of type
// 'void (D::*)()': different classes ('B' vs 'D')
}

The error message, at least on clang, is pretty clear. gcc just says cannot initialize. The issue is just that you cannot implicitly convert a pointer-to-derived-member to a pointer-to-base-member. But you can do it explicitly with static_cast:

void (B::*ptr)() = 
static_cast<void (B::*)()>(&D::foo); // ok!

Side-note: please remove the CALL_MBR_FUNC macro from your code and never write such a thing ever again.

Inheritance with Member Function Pointers and Templates

Simply deduce the entire parameter and extract its return type:

template<class F,class R=std::result_of_t<F(B&)>>
std::vector<R> getFunc(F&&){return{};}

std::result_of_t is C++14, for a C++11 compatible solution, use typename std::result_of<F(B&)>::type.

For a C++03 solution, simply deduce the class type:

template <typename T, typename C>
std::vector<T> getFunc(T (C::*func)());


Related Topics



Leave a reply



Submit