隐式转换为指向数据成员与非指针的指针
关于成员指针的大部分讨论都集中在成员所属的类型上允许的转换。 我的问题是关于成员类型的转换。
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可替代性原则:
Base*
的合同是:“我会给你一个基地”(当你使用*
运营商时)。 Derived*
的合同是“我会给你一个派生的,这也是一个基地”。
很明显Derived*
可以用来代替Base*
。 因此有一个从Derived*
到Base*
的隐式转换。
但请考虑指向成员的指针合约。
int Base::*
的合约是:“给我一个基地,我会给你一个int”(派生是一个基地,所以这些也可以) int Derived::*
的合约是:“给我一个派生,我会给你一个int“(但不是任何老Base
会做,它必须是Derived
)
想象一下,你有一个不是Derived
的Base
。 当取消引用int Base::*
时,它将很好地工作,但不能与int Derived*
)一起使用。
但是,如果您有Derived
,则可以使用它来取消引用int Base::*
和int Derived::*
。 因此,存在从int Base::*
到int Derived::*
的隐式转换
阿茹,我做了你所说的并分析了该成员所属的类型。
尽管LSP仍然有效。 我同意转换应该是合法的,至少根据类型安全。 合同是“给我一个Foo
,我会给你一个Derived
”,显然你可以用来从Foo
到Base
通过隐式转换来组合它。 所以它很安全。 DeadMG可能在正确的轨道上指出了与基本子对象的关系位置的潜在复杂性,特别是在虚拟继承中。 但是指针成员在解除引用运算符的LHS中处理这些问题,所以他们也可以得出结果。
最终答案可能只是标准不要求转换是合法的。
@Ben Voigt:你为什么挑出你的正确答案?
安全指针转换是反变换的,这意味着,您可以安全地向上转换,但不能向下转换。
指向会员转换的安全指针是同变异的,这意味着您可以安全地下注,但不能上传。
原因很容易看出来,当你想到它。 假设你有一个指向Base的成员的指针,这是Base的偏移量。 那么如果完整的对象是派生的,那么同一个成员到派生的偏移量是多少? 通常它的偏移量完全相同:当然,如果指向Base和Derived的指针是相同地址的话。 如果你有多重继承和虚拟基地,事情会变得更复杂:)
实际上,OP的示例代码就是上演演员阵容不安全的最佳例子:Derived类的成员的偏移量可以应用于任何Base,并指向基础子对象的末尾,如果该基础子对象的末尾实际上是Derived而不是Derived2。
有趣的问题。 数据指针很少使用,我对规则很不熟悉。
但是,我会把钱放在那是因为多重继承。 如果Base和Derived使用虚拟继承,编译器无法知道任何给定Derived中Base的偏移量,从而无法编译时偏移,并且将其合法化为非虚拟遗产。
链接地址: http://www.djcxy.com/p/3993.html上一篇: Implicit conversion for pointer to data member vs. non
下一篇: Where do we put the Servlets in the directory structure of Tomcat?