Напоследък опреснявам/актуализирам знанията си за C++ и научаването на стриктното псевдоним ме накара да съм малко предпазлив относно прехвърлянето на указатели от един тип към друг. Знам, че този примерен код по-долу работи на практика на моя компилатор, но искам да се уверя, че отговаря на текущите стандарти:
#include <iostream>
using namespace std;
class MyBase {
public:
virtual void DoSomething() = 0;
};
class MyDerived1 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #1" << endl;
}
};
class MyDerived2 : public MyBase {
public:
virtual void DoSomething() {
cout << "I'm #2" << endl;
}
};
template <typename Base, typename Member1, typename Member2>
struct Tuple {
public:
Base* Get(int i) {
return &(this->*(lookupTable[i]));
}
private:
Member1 member1;
Member2 member2;
static Base Tuple::* const lookupTable[2];
};
template <typename Base, typename Member1, typename Member2>
Base Tuple<Base, Member1, Member2>::* const Tuple<Base, Member1, Member2>::lookupTable[2] = {
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member1),
reinterpret_cast<Base Tuple<Base, Member1, Member2>::*>(&Tuple::member2)
};
int main() {
Tuple<MyBase, MyDerived1, MyDerived2> tuple;
tuple.Get(0)->DoSomething();
tuple.Get(1)->DoSomething();
return 0;
}
По същество този прост кортеж съдържа двойка елементи, всеки от които трябва да произлиза от общ базов клас. Функцията Get връща Base*
към члена, който даденият индекс представлява.
Ключовата част, за която се чудя, е reinterpret_casts. Знам, че прехвърлянето от Derived Struct::*
към Base Struct::*
е общо не-не, но в този случай използвам само променливата pointers-to-member, за да получа указател към обект. (Не се опитвам да копирам производен обект, сякаш е основен обект, нито да поставям основен обект в паметта на производен обект.) Това работи по предназначение на G++ и просто искам да съм сигурен, че не съм ще бъде ухапан от всички съвместими компилатори за това.