如何理解最终Overrider返回的类型被隐式转换为所谓的覆盖函数的返回类型?
按照 document
进行虚拟函数调用时,最终Overrider返回的类型将隐式转换为 返回类型的覆盖函数的返回类型,该函数称为 。。
如何以正确的方式理解这一点?
根据下面的演示代码的输出,似乎最终Overrider返回的类型取决于实例的静态类型(将调用成员函数)。
如果我想念什么,请告诉我。
这是 demo code timpet :
#include<iostream>
#include<typeinfo>
#define print() std::cout << __PRETTY_FUNCTION__ << std::endl;
class B {};
struct Base
{
virtual void vf1(){print();};
virtual void vf2(){print();};
virtual void vf3(){print();};
virtual B* vf4(){print();};
virtual B* vf5(){print();};
};
class D : private B
{
friend struct Derived; // in Derived, B is an accessible base of D
};
class A; // forward-declared class is an incomplete type
struct Derived : public Base
{
void vf1(){print();}; // virtual, overrides Base::vf1()
void vf2(int){print();}; // non-virtual, hides Base::vf2()
D* vf4(){print();}; // overrides Base::vf4() and has covariant return type
// A* vf5(){print();}; // Error: A is incomplete type
};
int main()
{
Derived d;
Base& br = d;
Derived& dr = d;
std::cout<<typeid(br.vf4()).name()<<std::endl; // calls Derived::vf4() and converts the result to B*
std::cout<<typeid(dr.vf4()).name()<<std::endl; // calls Derived::vf4() and does not convert the result to B*
B* p = br.vf4(); // calls Derived::vf4() and converts the result to B*
D* q = dr.vf4(); // calls Derived::vf4() and does not convert the result to B*
}
这是输出:
P1B
P1D
virtual D* Derived::vf4()
virtual D* Derived::vf4()
As per the document, which says that[emphasis mine]:
When a virtual function call is made, the type returned by the final overrider is implicitly converted to the return type of the overridden function that was called.
How to understand that in the right way?
According to the output of the demo code below, it seems that the type returned by the final overrider depends the static type of the instance (which the member function would be invoked on).
If I miss something, please let me know.
Here is the demo code snippet:
#include<iostream>
#include<typeinfo>
#define print() std::cout << __PRETTY_FUNCTION__ << std::endl;
class B {};
struct Base
{
virtual void vf1(){print();};
virtual void vf2(){print();};
virtual void vf3(){print();};
virtual B* vf4(){print();};
virtual B* vf5(){print();};
};
class D : private B
{
friend struct Derived; // in Derived, B is an accessible base of D
};
class A; // forward-declared class is an incomplete type
struct Derived : public Base
{
void vf1(){print();}; // virtual, overrides Base::vf1()
void vf2(int){print();}; // non-virtual, hides Base::vf2()
D* vf4(){print();}; // overrides Base::vf4() and has covariant return type
// A* vf5(){print();}; // Error: A is incomplete type
};
int main()
{
Derived d;
Base& br = d;
Derived& dr = d;
std::cout<<typeid(br.vf4()).name()<<std::endl; // calls Derived::vf4() and converts the result to B*
std::cout<<typeid(dr.vf4()).name()<<std::endl; // calls Derived::vf4() and does not convert the result to B*
B* p = br.vf4(); // calls Derived::vf4() and converts the result to B*
D* q = dr.vf4(); // calls Derived::vf4() and does not convert the result to B*
}
Here is the output:
P1B
P1D
virtual D* Derived::vf4()
virtual D* Derived::vf4()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
注意一词选择。称为的函数,而不是执行的函数。您的示例专注于执行相同的功能。所谓的功能取决于您如何放置呼叫(编译时间),而不是呼叫的回答(运行时间)。
对于类型
A&amp;
的参考ref
,expressionref.foo()
被调用为a :: foo()
a :: foo()< /代码>。呼叫后,多态性可能会启动并将执行重定向到另一个功能,但这并没有改变所谓的。您打电话给
a :: foo()
,但也许是b :: foo()
回答了呼叫。虚拟功能很棘手,彼此覆盖。你介意吗?并不真地。您对结果感兴趣,而不是谁提供。只要接听电话的函数尊重
a :: foo()
的合同,一切都很好。如果他们愿意,他们可以进行交易。在这个故事中,合同包括返回值的类型。这不能弄乱,否则呼叫堆栈被损坏。不幸的是,可能会有一个协变量的返回类型。幸运的是,
b :: foo()
知道,如果它涵盖a :: foo()
,它必须适应当前合同并进行隐式转换当它返回时免费。不用说。不过,
b
认为转换是降级。使用a
参考文献对步枪夫很好。让他们具有劣等的回报价值;好东西是为那些歧视b
参考的人保留的。这些优秀的人会致电b :: foo()
,并为他们跳过降级/转换。优雅。Note the word choice. The function that was called, not the function that was executed. Your examples focus on executing the same function. The function that was called depends on how you place the call (compile time), not how the call is answered (run time).
For a reference
ref
of typeA&
, the expressionref.foo()
is call toA::foo()
. After the call is made, polymorphism may kick in and redirect execution to a different function, but this does not change what was called. You calledA::foo()
, but maybe it wasB::foo()
that answered the call. Virtual functions are tricky like that, covering for each other.Do you mind? Not really. You are interested in results, not in who delivers them. As long as the function answering the call honors the contract made by
A::foo()
, all is fine. They can trade shifts if they wish.In this story, the contract includes the type of the returned value. This cannot be messed with, or else the call stack gets corrupted. Unfortunately, there might be a covariant return type in play. Fortunately,
B::foo()
knows that if it is covering forA::foo()
, it has to adapt to the current contract and throw in an implicit conversion gratis when it returns. It just goes without saying.Still,
B
considers the conversion a downgrade. It's fine for the riffraff usingA
references. Let them have their inferior return value; the good stuff is reserved for those discriminating few who insist uponB
references. These fine folks will callB::foo()
, and the downgrade/conversion is skipped for them. Classy.这是 @的答案。帮助它为其他读者提供帮助。
报价仅说明任何人都会期望什么:
dedived :: vf4
返回d*
。其他任何事情都会令人惊讶,因为D :: VF4被宣布返回D*。如果您考虑该基础:: vf4返回A B*,然后可能会想知道此调用
d* q = dr.vf4(); //派生:: vf4()的呼叫,并且不会将结果转换为b*
返回a b*,因为那就是base :: vf4返回。请记住,返回类型的超载功能必须匹配。使用多态性,呼叫者通常不知道或关心所谓的实际功能。他们仅依靠基础声明的界面,因此他们假设其a b*。不过,协变量的返回类型很特别。回报类型可能会有所不同。因为在示例中,b是d的私有基础,是依赖基界面的多态性的b* q = dr.vf4();甚至无法编译。
Here is the answer of @. Help it helps for other readers.
The quote only states what one would expect anyways:
Derived::vf4
returns aD*
. Anything else would be a surprise, because D::vf4 is declared to return a D*.If you consider that Base::vf4 returns a B* and then one might wonder whether this call
D* q = dr.vf4(); // calls Derived::vf4() and does not convert the result to B*
Returns a B* because thats what Base::vf4 returns. Remember that return type of overloaded functions must match. With polymorphism the caller typically does not know or care what is the actual function being called. They only rely on the interface as declared in Base so they assume its a B*. Though, covariant return types are special. The returns type can differ. Because in the example B is a private base of D, a polymorphic, relying on the Base interface, B* q = dr.vf4(); would even fail to compile.
帮助这篇文章的读者。
这是演示代码段:
这是上面的代码段的输出:
关于协变返回类型的一个有趣的注释:C ++无法动态选择类型。
在上面的示例中,我们首先致电d.getthis()。由于d是派生的,因此该调用派生:: getThis(),它返回派生*。然后,此派生*用于调用非虚拟函数派生:: printType()。
现在有趣的情况。然后,我们致电b-&gt; getthis()。变量B是指向派生对象的基本指针。 base :: getThis()是一个虚拟函数,因此该调用派生:: getThis()。尽管派生:: getThis()返回派生*,因为该函数的基本版本返回base*,但返回的派生*被启动到base*。因为base :: printType()是非虚拟的,所以调用base :: printType()。
换句话说,在上面的示例中,只有在用一个作为派生对象键入的对象调用getThis()时,您才会获得一个派生*。
请注意,如果printType()是虚拟的,而不是非虚拟的,则b-&gt; getThis()的结果(类型base*)的结果将经过虚拟函数分辨率,并将称为printType() 。
To help the readers of this post.
Here is demo code snippet:
Here is the output of the code snippet above:
One interesting note about covariant return types: C++ can’t dynamically select types, so you’ll always get the type that matches the actual version of the function being called.
In the above example, we first call d.getThis(). Since d is a Derived, this calls Derived::getThis(), which returns a Derived*. This Derived* is then used to call non-virtual function Derived::printType().
Now the interesting case. We then call b->getThis(). Variable b is a Base pointer to a Derived object. Base::getThis() is a virtual function, so this calls Derived::getThis(). Although Derived::getThis() returns a Derived*, because Base version of the function returns a Base*, the returned Derived* is upcast to a Base*. Because Base::printType() is non-virtual, Base::printType() is called.
In other words, in the above example, you only get a Derived* if you call getThis() with an object that is typed as a Derived object in the first place.
Note that if printType() were virtual instead of non-virtual, the result of b->getThis() (an object of type Base*) would have undergone virtual function resolution, and Derived::printType() would have been called.