c ++多态((X*)y) - > foo()vs((X)*y).foo()

5 c++ polymorphism

假设Y是来自类X的派生类,X将foo声明为虚拟.假设y是(Y*)类型.然后((X*)y) - > foo()将执行Y版本的foo(),但是((X)*y).foo()将执行X版本.你能告诉我为什么多态性不适用于解引用的案例吗?我希望任何一种语法都会产生Y版本的foo().

Joh*_*itb 10

您正在切割Y对象部件并将对象复制到X对象中.然后调用在X对象上调用的函数,从而X调用函数.

当您在声明或强制转换中指定C++中的类型时,这意味着声明或转换为对象实际上是该类型的对象,而不是派生类型.

如果你只想处理对象是类型的X(也就是说,如果你想要表达式的静态类型X,但仍希望它表示一个Y对象)那么你转换为引用类型

((X&)*y).foo()
Run Code Online (Sandbox Code Playgroud)

这将调用Y对象中的函数,并且不会切片或复制到X对象中.在步骤中,这样做

  • 解引用指针y,它的类型的Y*.解除引用会产生类型的左值表达式Y.一个左值表达实际上可以表示派生类型的对象,即使其静态类型是其底部的一个.
  • 投射到一个X&,这是一个参考X.这将产生类型的左值表达式X.
  • 调用该函数.

你原来的演员做了

  • 取消引用指针y.
  • 结果表达式转换为X.这将导致复制操作到新X对象.结果表达式是静态类型的右值表达式X.表示的对象的动态类型 X与所有rvalue表达式一样.
  • 调用该函数.


Ste*_*sop 8

转换always(*)创建一个您要转换为的类型的新对象,该对象是使用您正在转换的对象构造的.

转换为X*会创建一个新指针(即X*类型的对象).它具有相同的值y,因此它仍指向Y类型的同一对象.

转换为X会创建一个新的X.它是使用构造的*y,但它与旧对象无关.在你的例子中,foo()在这个新的"临时"对象上调用,而不是在指向的对象上调用y.

你是正确的,动态多态只适用于指针和引用,而不适用于对象,这就是为什么:如果你有一个指向X的指针,那么它指向的东西可能是X的子类.但是如果你有一个X,然后它是一个X,没有别的.虚拟通话毫无意义.

(*)除非优化允许省略不改变结果的代码.但是不允许优化改变foo()调用的函数.


Sea*_*ean 0

我相信这只是由于语言的指定方式所致。引用和指针尽可能使用后期绑定,而对象则使用早期绑定。在每种情况下都可以进行后期绑定(我想),但是这样做的编译器不会遵循 C++ 规范。