为什么作用域解析运算符(:)不允许虚拟函数机制?否则可能导致无限递归 我从Bjarne Stroustrup的《C++编程语言》一书中了解到虚拟函数,遇到了下面的代码片段:-< /p> class A { //... protected: int someOtherField; //... public: virtual void print() const; //... }; class B : public A { //... public: void print() const; //... }; void B::print() const { A::print(); cout<<A::someOtherField; //... }
否则,B::print()将遭受无限递归 这是指没有为什么作用域解析运算符(:)不允许虚拟函数机制?否则可能导致无限递归 我从Bjarne Stroustrup的《C++编程语言》一书中了解到虚拟函数,遇到了下面的代码片段:-< /p> class A { //... protected: int someOtherField; //... public: virtual void print() const; //... }; class B : public A { //... public: void print() const; //... }; void B::print() const { A::print(); cout<<A::someOtherField; //... },c++,class,oop,class-hierarchy,scope-resolution-operator,C++,Class,Oop,Class Hierarchy,Scope Resolution Operator,否则,B::print()将遭受无限递归 这是指没有A::的代码: void B::print() const { print(); cout<<A::someOtherField; //... } void B::print()常量{ 打印(); cout如果限定调用A::print()没有禁用虚拟分派,那么B::print()中的用法将是无限递归,并且从基类调用函数几乎是不可能的 如果限定调用未禁用虚拟分派,请参阅虚拟代码执行: 您有A*A=新B;
A::
的代码:
void B::print() const {
print();
cout<<A::someOtherField;
//...
}
void B::print()常量{
打印();
cout如果限定调用A::print()
没有禁用虚拟分派,那么B::print()
中的用法将是无限递归,并且从基类调用函数几乎是不可能的
如果限定调用未禁用虚拟分派,请参阅虚拟代码执行:
您有A*A=新B;
调用了a->print()
,虚拟分派确定应调用B::print()
B::print()
的第一条指令调用A::print()
,虚拟分派确定应调用B::print()
无限递归
现在,当限定调用禁用虚拟分派时的执行序列:
您有A*A=新B;
调用了a->print()
,虚拟分派确定应调用B::print()
B::print()
的第一条指令调用A::print()
,正好调用了这个函数
A::print()
完成它的工作并完成
B::print()
继续执行
没有递归发生
这不会导致无限递归。在“否则,B::print()将遭受无限递归”中,“否则”表示不使用:
。如果:
未禁用虚拟调度,则编写A::print()
将调用B::print(),因为,后者优于前者。这里有许多微妙的问题,每个都说明了为什么C++会如此危险——为什么在C++中经常如此、非常容易地无意地编写有缺陷的代码。因此需要使用作用域操作符对其进行限定。@HolyBlackCat Nit:B::print
不会覆盖A::print
,是吗?A::print
不是虚拟的B::print
隐藏A::print
,例如A&&x=B();x.print();
通过静态调度调用A::print
。“禁用虚拟调度”与“绕过虚拟调度”不同,这里只演示了后者。在我看来,“禁用虚拟调度”只有在A::print
也是virtual
@HolyBlackCat时才会显示。这怎么会发生(调用A::print()将调用B::print()),在这里,我明确告诉您调用基类的方法?请您详细说明您的答案,这将对我有很大帮助。我是C++的初学者,不仅是递归函数,而且是没有退出条件的递归函数。因此无限。第一次调用print()将使用动态调度机制,但当明确声明调用A::print()时,为什么它再次使用该机制?虚拟机制是否用于实例对象发起的所有调用?@AnkitKumar第一个序列是假设的-如果A::print()会发生什么情况
没有阻止虚拟分派。如果我误解了你的问题,很抱歉。你的回答正确,谢谢你,但我不明白的是,对print()的每个调用(假设!)都会使用动态分派机制吗?在这种情况下,即使它在B::print()内部?我能断定每个调用都会被一些编译器的“vptr”?这是否意味着创建了一个非物理的print(),它只为所有其他print()提供了一个抽象接口?@Ankit是的,当print()时,每次对print()的非限定调用
是虚拟的
,将使用动态分派。详细说明编译器如何处理特定于实现的问题,但大多数都将vptr作为隐藏成员添加到类对象,并为内存中某处具有virtual
函数的每个类添加一个公共vtable。然后调用print()
将被编译器替换为vptr[functionId]
并且根据vptr
是什么,将调用来自正确vtable的函数。最后一个疑问是,为什么在void B::print()常量{}内的A::print()调用使用虚拟机制,因为它有资格显式调用父方法?谢谢
void B::print() const {
print();
cout<<A::someOtherField;
//...
}