struct Base{}; struct Derived : public Base{}; struct Foo{ Derived m_Derived; };
// error C2440: 'initializing' : cannot convert from 'Derived Foo::* ' to 'Base Foo::* ' Base Foo::*p = &Foo::m_Derived;
从Derived *到Base *的转换通常是允许的 – 为什么差异在这里?
解决方法
返回类型隐式转换为基类型(逆变).但是参数隐式转换为派生类型(协方差),并且指向成员的指针中的类类型充当参数.为了看到这一点,让我们应用Liskov Substitutability原则:
Base *的合同是:“我会给你一个基地”(当你在我身上使用*运算符时).
Derived *的合同是“我会给你一个Derived,这也是一个基础”.
显然,可以使用Derived *代替Base *.因此,存在从Derived *到Base *的隐式转换.
但考虑指向成员的合同.
int Base :: *的契约是:“给我一个Base,我会给你一个int”(A Derived是一个Base,所以那些也可以)
int Derived :: *的契约是:“给我一个派生,我会给你一个int”(但不是任何旧的Base都会做,它必须是Derived)
想象一下,你有一个不是派生的基础.取消引用int Base :: *时它会很好地工作,但不能与int Derived *一起使用.
但是,如果您有Derived,则可以使用它来取消引用int Base :: *和int Derived :: *.因此,存在从int Base :: *到int Derived :: *的隐式转换
唉,我做了你说的话,并分析了该成员所属的类型.
LSP仍然有效.我同意转换应该是合法的,至少根据类型安全.合同是“给我一个Foo,我会给你一个Derived”,显然你可以通过用隐式转换组合来从Foo到Base.所以这很安全. DeadMG可能在正确的轨道上指出了基础子对象的关系位置的潜在复杂性,尤其是在虚拟继承中.但指向成员的指针在解除引用运算符的LHS上处理这些问题,因此它们也可以用于结果.
最后的答案可能只是标准不要求转换是合法的.