为什么作用域解析运算符(:)不允许虚拟函数机制?否则可能导致无限递归 我从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; //... }

为什么作用域解析运算符(:)不允许虚拟函数机制?否则可能导致无限递归 我从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;

否则,B::print()将遭受无限递归

这是指没有
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;
         //...
    }