Confusion over name hiding and virtual functions

Link to another question so

Consider the code:

class Base { public: virtual void gogo(int a){ printf(" Base :: gogo (int) \n"); }; virtual void gogo(int* a){ printf(" Base :: gogo (int*) \n"); }; }; class Derived : public Base{ public: virtual void gogo(int* a){ printf(" Derived :: gogo (int*) \n"); }; }; int main(){ // 1) Derived * obj = new Derived ; obj->gogo(7); // this is illegal because of name hiding // 2) Base* obj = new Derived ; obj->gogo(7); // this is legal } 

In case 2)

The call to obj->gogo(7) allowed at runtime.

Since obj->gogo(7) is legal. It seems that the Derived table vtable contains ptr up to virtual void gogo(int a) , which should have been hidden.

My confusion is that since hiding the name causes case 1) to be illegal, then how the call to 2) is allowed at runtime

a) Does vtable Derived have a pointer to gogo (int).

b) If a) is not True, does the call allow virtual functions of the vtable of the base class.

+6
source share
4 answers

You confuse virtual function calls and overload resolution.

All derived classes have vtables containing all virtual functions from the base class and any additional native virtual functions. This is used to resolve calls at runtime , for example, in your case 2).

In case 1) you get an error from overload resolution at compile time . Because of the name hiding, the Derived class has only one function called. Your only choice is to call this function with int* .

+5
source

You want to override the overloaded function, but the hide rules do not work.

"The hiding rule states that an object in the inner area hides objects with the same name in the outer region."

Please note: it does not matter that it has a different signature, i.e. gogo(int* a) will hide all gogo(whatever) functions from the base. Overriding happens only when your functions have the same name, same signatures, and virtual ones (so only gogo(int* a) will be canceled).

The C ++ FAQ book suggests the use of "non-virtual overloads that cause unloaded virtual machines." (chapter 29.05). Basically you create non-virtual overloaded functions in the base class:

gogo(int a) and gogo(int* a)

which will call virtual functions accordingly:

virtual gogo_i (int a) and virtual gogo_pi (int * a)

And override these virtual machines in the Derived class.

+2
source

In principle, function overloading occurs only when functions of the same name are defined in the same area. The Base class now has its own scope, and the derived class has its own.

So, when u does not redefine a function in a derived class and does not call this function, the compiler checks the region of derivatives, finds that it does not have such a function. Then it checks the scope of the base class, discovers the function, and accordingly associates the function call with this specific definition.

But, when u redefines a function with a different signature, the compiler matches the call with this function, sees the inconsistency and just complains.

you can change this behavior by adding "using Base :: gogo;" in defenision of a derived class. Hope this explains.

+1
source

Since you declared the second obj as Base* , vtable gives all the Base methods. Although overridden versions are called for virtual methods that were exceeded using Derived , other methods (or method overloads) are still those that were declared in Base .

However, if you specify the pointer as Derived* , vtable will provide it with Derived methods, hiding those that have the same name in Base . Consequently, obj->gogo(7); will not work. Similarly, it is illegal:

 Base* obj = new Derived(); // legal, since obj is a pointer to Base, it contains the gogo(int) method. obj->gogo(7); // illegal, it has been cast into a pointer to Derived. gogo(int) is hidden. (reinterpret_cast<Derived*>(obj))->gogo(7); 

It is legal:

 Derived* obj = new Derived ; obj->Base::gogo(7); // legal. 

See here .

0
source

Source: https://habr.com/ru/post/913315/


All Articles