I'd like to downcast a pointer to a member function, where the base class is inherited virtually. This leads to an error at compile time.
In my application, I have a collection of several objects (e.g. D1
, D2
), that have a common base class B
. They are held together and kept track of by means of a std::vector<B*>
.
The derived objects introduce double
-returning functions that need to be called on a regular basis. The base class keeps track of these functions by means of a std::vector<double(B::*)(void)>
. The whole chain is utilized in the second to last line of the main function.
Therefore, I needed to cast the function pointers when adding them to the vector, as is done in the constructor of the derived classes D1
and D2
. his is successful in case of D1
, but not in case of D2
, as B
is a virtual base of D2
. As I learned, a static cast does not work in this case (error message 1), because the deriving classes D21
and D22
only have a pointer to the instance of B
. However, a dynamic_cast also leads to an error at compile time (error message 2), saying that the target is not of pointer type.
error message 1: error: pointer to member conversion via virtual base 'B' v.push_back(static_cast(&D2::f2));
error message 2: error: cannot dynamic_cast '&D2::f2' (of type 'double (class D2::)()') to type 'double (class B::)()' (target is not pointer or reference)
I'd like to know how, if at all, I can perform the desired cast. If not I'd like to know why such a thing is not possible.
Edit: Some background: I integrate a system of ordinary differential equations numerically. The derived classes represent the individual equations of the system, and each derived class computes its own state. By collecting the classes in the vector o
, I can quickly modify the system of equations. The vector v
in the base class is needed for output purposes. During integration, each subsystem also takes care of its own output through the base class. The diamond arose because I separated two often used pieces of code into two individual classes.
Arguably, there are other ways to design the class hierarchy, and there are other ways to achieve my goal (in this case I made the function p
in B
virtual, and re-implemented it in the deriving classes). However, I could not fathom why the cast failed, so I asked the question.
MWE:
#include <vector>
#include <algorithm>
#include <iostream>
// Base class
class B {
protected:
std::vector<double(B::*)(void)> v;
public:
void p ( void )
{for_each(v.begin(), v.end(), [this] (double (B::*f) (void)) {std::cerr << (this->*f)() << std::endl;});};
};
// Normal inheritance
class D1: public B
{public:
double f1 ( void ) { return 1; }
D1() { v.push_back(static_cast<double(B::*)(void)>(&D1::f1));} // Casting is successful here.
};
// Setting up 'the diamond'
class D21: virtual public B {};
class D22: virtual public B {};
class D2: public D21, public D22
{public:
double f2 ( void ) { return 2; }
D2() { v.push_back(dynamic_cast<double(B::*)(void)>(&D2::f2)); } // How to cast here?
};
int main ()
{
// Vector holding the classes together
std::vector<B*> o;
// Set up the system
D1 d1;
D2 d2;
o.push_back(&d1);
o.push_back(&d2);
// Derived functions are called
for_each(o.begin(),o.end(),[] (B *o) {o->p();});
return 0;
}