背景:多くの関数型言語は代数データ型をサポートしており、仮想関数と継承である程度エミュレートできます。
派生型のサイズが異なるため、最も明白な解決策はヒープの割り当てです。ただし、ユニオンを使用して、追加の割り当てなしでスタック上の最大の型を保持できるはずです。これには、ベースへの追加のポインターを共用体と共に格納する必要があり、同時にコピーと代入が複雑になります。
アクティブなユニオン メンバーを指すユニオンの先頭からのオフセットとしてメンバー セレクターを格納することにより、後者の問題を解決することは非常に重要です。C++には、各メンバーへのポインターが異なる型を持つことを除いて、目的にほぼ適合しているように見えるメンバーポインターがあります。
質問: Derived T::* を Base T::* にキャストできないのはなぜですか?
上記とは関係のない、同じ制限にぶつかるおもちゃの例を次に示します。
struct fish {};
struct shark : public fish {};
struct trout : public fish {};
struct aquarium
{
shark shark;
trout trout;
};
fish aquarium::* pick_dinner(bool dangerous = true)
{
if (dangerous)
{
return &aquarium::shark;
}
return &aquarium::trout;
}
#include <iostream>
void cook(fish&)
{
std::cerr << "Do it yourself\n";
}
int main()
{
aquarium spherical, hexagonal;
fish aquarium::*ingredient = pick_dinner();
cook(spherical.*ingredient);
cook(hexagonal.*ingredient);
}
生成されたコンパイル エラー:
main.cpp:15:16: error: cannot initialize return object of type 'fish aquarium::*' with an rvalue of type 'shark aquarium::*'
return &aquarium::shark;
^~~~~~~~~~~~~~~~
main.cpp:17:12: error: cannot initialize return object of type 'fish aquarium::*' with an rvalue of type 'trout aquarium::*'
return &aquarium::trout;
^~~~~~~~~~~~~~~~
2 errors generated.