Polymorphic pointer to member variables
-
16-12-2020 - |
Question
I'm trying to use pointers to member variables in a polymorphic fashion.
This works:
struct Foo
{
int member0;
int member1;
int* getMember( int i )
{
static int Foo::* table[2] = { &Foo::member0, &Foo::member1 };
return &( this->*table[i] );
}
};
This does not, since the members are not of the same type (BaseClass):
struct Foo
{
SubClassA member0;
SubClassB member1;
BaseClass* getMember( int i )
{
static BaseClass Foo::* table[2] = { &Foo::member0, &Foo::member1 };
return &( this->*table[i] );
}
};
The error reported by g++ is:
[...] invalid conversion from 'SubClassA Foo::*' to 'BaseClass Foo::*'
[...] invalid conversion from 'SubClassB Foo::*' to 'BaseClass Foo::*'
Is there a way to make this work, ie to "upcast" the member pointer to its base class?
Solution
This is not possible. Because of multiple inheritance, address-of-base is not always the same as address-of-derived. You need some hidden address adjustment magic to convert one to the other, and a pointer-to-member, being a very simple object (basically an integer offset) cannot accomodate this magic.
It is true that address adjustment only needed sometimes, and when it is not needed, polymorphic pointers-to-members could in principle be allowed. But this is not done, for simplicity and consistency.
Instead of pointers-to-members, you can use pointers to functions (or function-like objects) that accept a Foo* and return a BaseClass*. You will have to make a separate function for each member though.
OTHER TIPS
BaseClass* getMember(const int i)
{
switch(i)
{
case 0: return &member0;
case 1: return &member1;
default: throw <exception>;
}
}
For robustness you have to anyway check if the i
is within the range or 0 and 1; so you can think for this simplified approach.
The easier way to do it would be to skip the member data pointers altogether.
getMember(int i) {
BaseClass* ptr[2] = { &member0, &member1 };
return ptr[i];
}