C ++ virtual function call without pointer or reference

As far as I know, calling a virtual function usually requires a pointer or reference. Therefore, 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(); } 

Output signal

D

Can someone comment on why this virtual function call works? Thanks.

+7
c ++ pointers reference virtual
source share
3 answers

Inside a member function, any references to other member functions or variables are implicitly resolved using the this pointer. Thus, in the definition of runB() value of call() really means this->call() . A virtual function call is made using the virtual table of the current object.

+11
source share

First, calling a virtual function does not require a pointer or reference. As for the language, any call to a virtual function is a virtual call, unless you explicitly suppress the virtual sending mechanism using the name of the qualified function. For example, these

 dD::call(); // calls `D::call()` directly dB::call(); // calls `B::call()` directly 

- These are challenges that were clearly forced to be non-virtual. However this

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

- virtual call. In this case, it immediately becomes apparent to the compiler that the target function is D::call() , so the compiler usually optimizes this virtual call into a regular direct call. Conceptually, however, d.call() is still a virtual call.

Secondly, the call() made inside B::runB() is made using a pointer. The pointer is present there implicitly. The call() notation inside B::runB() is just a shorthand for (*this).call() . this is a pointer. Thus, the call is made using the pointer.

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

Fourth, you really need a pointer or link to observe the actual polymorphism. Native polymorphism occurs when the static type of an expression of an object used in a call is different from its dynamic type. To do this, you really need a pointer or link. And this is exactly what you observe in this call (*this).call() inside B::runB() . Although the static *this type is B , its dynamic type is D , and the call is sent to D::call() .

+7
source share

The difference between virtual and not virtual:

not virtual - always follows the object / reference / pointer type of the calling object.

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

virtual - object - performed by the caller.

eg:

 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; af(); //A: caller type = created type - same for not virtual bf(); //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
source share

All Articles