【问题标题】:c++ virtual function call without pointer or referencec++ 没有指针或引用的虚函数调用
【发布时间】:2014-10-06 06:00:46
【问题描述】:

据我所知,虚函数调用通常需要指针或引用。所以我对以下代码感到非常惊讶。

#include <iostream>
using namespace std;
class B{
public:
  void runB(){        call();  }
  virtual void call(){ cout<<"B\n"; };
};

class D: public B{
public:
  void runD(){       runB();   }
  void call(){       cout<<"D\n";  }
};

int main(){
 D d;
 d.runD();
}

输出是

D

有人可以评论一下为什么这个虚函数调用有效吗?谢谢。

【问题讨论】:

  • 你预计会发生什么?
  • 你有一个呼叫指针:this
  • 扩展 chris 的评论:在每个类的内部方法中,总是有一个 *this 的隐式指针。所以call()this-&gt;call() 在你的代码中是一样的。
  • 虚拟函数和其他函数一样,唯一的区别是关键字“虚拟”。因此所有函数都具有相同的属性,您可以将它们定义为 void 或返回语句。

标签: c++ pointers reference virtual


【解决方案1】:

在成员函数中,对其他成员函数或变量的任何引用都通过this 指针隐式解析。所以在runB() 的定义中,call() 真正的意思是this-&gt;call()。虚函数调用是使用当前对象的虚表进行的。

【讨论】:

    【解决方案2】:

    virtual 和 not virtual 的区别是:

    不是虚拟的 - 总是按照调用者对象/引用/指针类型。

    virtual - 引用/指针 - 根据创建的对象类型。

    虚拟 - 对象 - 由调用者处理。

    例如:

    class A{
    public:
        virtual void f(){
            cout <<"A\n";
        }
    };
    class B: public A{
    public:
        virtual void f(){
            cout <<"B\n";
        }
    };
    
    
    B b;
    A a,*pa=&b;
    a.f(); //A: caller type = created type - same for not virtual
    b.f(); //B: caller type = created type - same for not virtual
    ((A)b).f(); //A: object goes by the caller type - same for not virtual
    pa->f(); // B: pointer goes by the created type - it would be A if it was not virtual!!
    

    【讨论】:

      【解决方案3】:

      首先,虚函数调用不需要指针或引用。就语言而言,任何对虚函数的调用都是虚调用,除非您通过使用限定函数名显式抑制虚调度机制。比如这些

      d.D::call(); // calls `D::call()` directly
      d.B::call(); // calls `B::call()` directly
      

      是被明确强制为非虚拟的调用。然而,这

      d.call(); // calls `D::call()` virtually
      

      是一个虚拟呼叫。在这种情况下,编译器很明显目标函数是D::call(),因此编译器通常会将此虚拟调用优化为常规直接调用。然而,从概念上讲,d.call() 仍然是一个虚拟呼叫。

      其次,在B::runB() 内部对call() 的调用是通过指针进行的。指针隐含地存在在那里。在B::runB() 中写入call() 只是(*this).call() 的简写。 this 是一个指针。所以调用 是通过指针进行的。

      第三,虚调用的关键属性是目标函数是根据调用中使用的对象的动态类型来选择的。在您的情况下,即使您在B::runB() 内部,对象*this 的动态类型也是D。这就是它应该调用D::call() 的原因。

      第四,您真正需要的指针或引用是观察实际的多态性。当调用中使用的对象表达式的静态类型与其动态类型不同时,就会发生多态性。为此,您确实需要一个指针或引用。这正是你在(*this).call() 调用B::runB() 中观察到的。即使*this 的静态类型是B,它的动态类型是D 并且调用被调度到D::call()

      【讨论】:

        猜你喜欢
        • 2013-02-28
        • 1970-01-01
        • 1970-01-01
        • 2011-06-17
        • 1970-01-01
        • 1970-01-01
        • 2011-10-08
        • 1970-01-01
        • 2012-04-16
        相关资源
        最近更新 更多