c++虚函数调用,没有指针或引用

时间:2022-03-28 16:57:08

As far as I know, virtual function call usually requires pointer or reference. So I am very surprised by the following codes.

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

#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();
}

The output is

输出是

D

D

Could someone please comment why this virtual function call works? Thanks。

有人能解释一下这个虚拟函数调用为什么有效吗?谢谢。

3 个解决方案

#1


11  

Within a member function, any references to other member functions or variables are implicitly resolved via the this pointer. So in the definition of runB(), the call() really means this->call(). The virtual function call is performed using the current object's virtual table.

在成员函数中,任何对其他成员函数或变量的引用都通过这个指针隐式解析。所以在runB()的定义中,call()实际上是指这个->调用()。使用当前对象的虚拟表执行虚函数调用。

#2


8  

Firstly, virtual function call does not require a pointer or a reference. As far as the language is concerned, any call to virtual function is a virtual call, unless you explicitly suppress the virtual dispatch mechanism by using a qualified function name. For example, these

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

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

are calls which were explicitly forced to be non-virtual. However, this

是显式强制非虚的调用。然而,这

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

is a virtual call. In this case it is immediately obvious to the compiler that the target function is D::call(), so the compiler normally optimizes this virtual call into a regular direct call. Yet, conceptually, d.call() is still a virtual call.

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

Secondly, the call to call() made inside B::runB() is made through a pointer. The pointer is present there implicitly. Writing call() inside B::runB() is just a shorthand for (*this).call(). this is a pointer. So that call is made through a pointer.

其次,调用B::runB()中的call()是通过一个指针进行的。指针隐式地显示在那里。在B::runB()中写入call()只是(*this).call()的简写。这是一个指针。这个调用是通过一个指针进行的。

Thirdly, the key property of virtual call is that the target function is chosen in accordance with the dynamic type of the object used in the call. In your case, even when you are inside B::runB() the dynamic type of the object *this is D. Which is why it calls D::call(), as it should.

第三,虚拟调用的关键属性是根据调用中使用的对象的动态类型选择目标函数。在您的例子中,即使您在B::runB()对象的动态类型*this is D,这就是它调用D::call()的原因,因为它应该这样。

Fourthly, what you really need a pointer or a reference for is to observe the actual polymorphism. Polymorphism proper occurs when static type of the object expression used in the call is different from its dynamic type. For that you do indeed need a pointer or a reference. And that is exactly what you observe in that (*this).call() call inside B::runB(). Even though the static type of *this is B, its dynamic type is D and the call is dispatched to D::call().

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

#3


3  

The difference between virtual to not virtual is:

虚拟与非虚拟的区别是:

not virtual - always goes by the caller object/reference/pointer type.

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

virtual - reference/pointer - goes by the created object type.

虚拟-引用/指针-由创建的对象类型进行。

virtual - object - goes by the caller.

虚拟对象——由调用者执行。

for example:

例如:

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!!

#1


11  

Within a member function, any references to other member functions or variables are implicitly resolved via the this pointer. So in the definition of runB(), the call() really means this->call(). The virtual function call is performed using the current object's virtual table.

在成员函数中,任何对其他成员函数或变量的引用都通过这个指针隐式解析。所以在runB()的定义中,call()实际上是指这个->调用()。使用当前对象的虚拟表执行虚函数调用。

#2


8  

Firstly, virtual function call does not require a pointer or a reference. As far as the language is concerned, any call to virtual function is a virtual call, unless you explicitly suppress the virtual dispatch mechanism by using a qualified function name. For example, these

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

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

are calls which were explicitly forced to be non-virtual. However, this

是显式强制非虚的调用。然而,这

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

is a virtual call. In this case it is immediately obvious to the compiler that the target function is D::call(), so the compiler normally optimizes this virtual call into a regular direct call. Yet, conceptually, d.call() is still a virtual call.

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

Secondly, the call to call() made inside B::runB() is made through a pointer. The pointer is present there implicitly. Writing call() inside B::runB() is just a shorthand for (*this).call(). this is a pointer. So that call is made through a pointer.

其次,调用B::runB()中的call()是通过一个指针进行的。指针隐式地显示在那里。在B::runB()中写入call()只是(*this).call()的简写。这是一个指针。这个调用是通过一个指针进行的。

Thirdly, the key property of virtual call is that the target function is chosen in accordance with the dynamic type of the object used in the call. In your case, even when you are inside B::runB() the dynamic type of the object *this is D. Which is why it calls D::call(), as it should.

第三,虚拟调用的关键属性是根据调用中使用的对象的动态类型选择目标函数。在您的例子中,即使您在B::runB()对象的动态类型*this is D,这就是它调用D::call()的原因,因为它应该这样。

Fourthly, what you really need a pointer or a reference for is to observe the actual polymorphism. Polymorphism proper occurs when static type of the object expression used in the call is different from its dynamic type. For that you do indeed need a pointer or a reference. And that is exactly what you observe in that (*this).call() call inside B::runB(). Even though the static type of *this is B, its dynamic type is D and the call is dispatched to D::call().

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

#3


3  

The difference between virtual to not virtual is:

虚拟与非虚拟的区别是:

not virtual - always goes by the caller object/reference/pointer type.

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

virtual - reference/pointer - goes by the created object type.

虚拟-引用/指针-由创建的对象类型进行。

virtual - object - goes by the caller.

虚拟对象——由调用者执行。

for example:

例如:

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!!