私は最近、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::*
to からto へのキャストBase Struct::*
は一般的に禁止されていることはわかっていますが、この場合は、ポインターからメンバーへの変数のみを使用して、オブジェクトへのポインターを取得します。(派生オブジェクトをベース オブジェクトであるかのようにコピーしたり、ベース オブジェクトを派生オブジェクトのメモリに詰め込もうとしたりしません。) これは G++ で意図したとおりに機能し、そうでないことを確認したいだけです。これを行うために、準拠しているコンパイラに噛まれます。