Confusion regarding name hiding and virtual functions
Asked Answered
B

4

7

Refering another so question

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
}

For case 2)

The call obj->gogo(7) is resolved at run time.

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

My confusion is , since name hiding causes case 1) to be illegal, then how the call in 2) is resolved at run time

a) Does vtable of Derived contains pointer to gogo(int).

b) If a) is not True, Does call resolution for virtual functions proceeds to vtable of base class.

Brewery answered 16/4, 2012 at 11:26 Comment(2)
@AndersK The function Base::gogo(int) is indeed hidden by Derived::gogo(int*). But a using Base::gogo; statement in the Derived class would solve this particular problem.Typical
@MichaelWild yep, i saw my mistake.Haggadist
M
5

You are confusing virtual functions calls and overload resolution.

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

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

Mithgarthr answered 16/4, 2012 at 11:48 Comment(6)
No there is no error. Since both gogo() overloads were declared in Base, overriding one won't hide the other one.Ophthalmoscopy
this does explains above behavior. Does c++ standard ( or any book/document) describes same thing. I mean is it possible to get a citation.Hick
@fizzbuzz - A name declared in an inner scope always hides a name in an outer scope. In this case the derived class is the inner scope and the base class the outer scope.Mithgarthr
@Bo "All derived classes have vtables containing all virtual functions, from the base class and any additional own virtual functions" Any citation for this?Brewery
@hitesg - No, there is nothing in the standard about vtables at all. It is just an implementation option (which currently all known compilers use).Mithgarthr
@hitesg - Try this for an explanation http://en.wikipedia.org/wiki/Virtual_table#ImplementationMithgarthr
P
2

You want to override overloaded function but hiding rules don't work like this.

"The hiding rule says that an entity in an inner scope hides things with the same name in an outer scope."

Note, it is irrelevant that it has different signature i.e. gogo(int* a) will hide all gogo(whatever) functions from the Base. Overriding occurs only when your functions have same name, same signatures and virtual (so, only gogo(int* a) will be overrided).

The C++FAQ book suggest to use "non-virtual overloads that call non-overloaded virtuals." (chapter 29.05). Basically you create non-virtual overloaded functions in base class:

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

which will call virtual functions respectively:

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

And override this virtuals in Derived class.

Poppycock answered 16/4, 2012 at 13:3 Comment(0)
F
1

Basically, function overloading happens only when the functions of same name are defined in the same scope.Now, Base class has its own scope and derived class has its own.

So, when u don't redefine a function in the derived class and call that function, the compiler checks the scope of derived, discovers that there is no such function defined in there. Then it checks the scope of base class, discovers the function and accordingly binds the function call to this particular definition.

But, when u redefine the function with different signature, the compiler matches the call with this function, sees inconsistency and simply complains.

you can change this behaviour by adding "using Base::gogo; " in derived class defenision. I hope this explains.

Favor answered 16/4, 2012 at 12:13 Comment(0)
D
0

Since you declared the second obj as a Base*, the vtable gives it all the methods of Base. Although for virtual methods which have been overriden by Derived, the overriden versions are called, the other methods (or method overloads) are still those that have been declared in Base.

However, if you declared the pointer as Derived*, the vtable will give it the methods of Derived, hiding the ones that had the same name in Base. Hence, obj->gogo(7); will not work. Similarly, this is also 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);

This is legal:

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

See here.

Doubleton answered 16/4, 2012 at 11:35 Comment(2)
Wouldn't be dynamic_cast more appropriate in your example?Marquez
As far as I know this has nothing to do with the actual vtable lookup but with static typing and name hiding (see Bo Persson's answer). If type is Derived, those semantics apply, if type is Base, other semantic applies.Mariehamn

© 2022 - 2024 — McMap. All rights reserved.