背景:许多函数式语言支持代数数据类型,在一定程度上可以用虚函数和继承来模拟。
最明显的解决方案涉及堆分配,因为派生类型具有不同的大小。但是,我们应该能够使用联合来保存堆栈上最大的类型,而无需任何额外分配。这需要一个额外的指向基址的指针与联合一起存储,同时使复制和赋值复杂化。
通过将成员选择器存储为从指向活动联合成员的联合开始的偏移量来解决后一个问题是令人信服的。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.