c – 指向数据成员与非成员的指针的隐式转换

前端之家收集整理的这篇文章主要介绍了c – 指向数据成员与非成员的指针的隐式转换前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我见过的关于成员指针的大多数讨论都集中在成员所属类型允许的转换上.我的问题是关于成员类型的转换.
struct Base{};
struct Derived : public Base{};
struct Foo{ Derived m_Derived; };

鉴于这些声明,以下代码会产生错误(MSVC 2008):

// 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上处理这些问题,因此它们也可以用于结果.

最后的答案可能只是标准不要求转换是合法的.

猜你在找的C&C++相关文章