Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the differences between overriding virtual functions and hiding non-virtual functions?

Given the following code fragment, what are the differences in the function calls? What is function hiding? What is function overriding? How do they relate to function overloads? What is the difference between the two? I couldn't find a good description of these in one place, so I'm asking here so I can consolidate the information.

class Parent {   public:     void doA() { cout << "doA in Parent" << endl; }     virtual void doB() { cout << "doB in Parent" << endl; } };  class Child : public Parent {   public:     void doA() { cout << "doA in Child" << endl; }     void doB() { cout << "doB in Child" << endl; } };  Parent* p1 = new Parent(); Parent* p2 = new Child(); Child* cp = new Child();  void testStuff() {   p1->doA();   p2->doA();   cp->doA();    p1->doB();   p2->doB();   cp->doB(); } 
like image 384
Jed Schaaf Avatar asked Nov 01 '13 22:11

Jed Schaaf


People also ask

What is the difference between overriding and virtual function?

The virtual keyword can be used when declaring overriding functions in a derived class, but it is unnecessary; overrides of virtual functions are always virtual. Virtual functions in a base class must be defined unless they are declared using the pure-specifier.

What is difference between virtual and non-virtual overriding?

With the virtual keyword on the base class method and the override keyword on the method in the derived class, both methods are said to be virtual. Methods that don't have either the virtual or override keywords, or that have the new keyword, are said to be non-virtual.

How do you override non-virtual functions?

So for example if you created an instance of your derived class but called your 'Display' method via a pointer to the base class, the base's method will be called, whereas for 'vDisplay' the derived method would be called. Base *b = &ba; b->Display(); b->vDisplay(); b = &de; b->Display(); b->vDisplay();

What is the difference between virtual function and normal function?

Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object. In contrast, virtual member functions are resolved dynamically (at run-time).


2 Answers

What is function hiding?

... is a form of name hiding. A simple example:

void foo(int); namespace X {     void foo();          void bar()     {         foo(42); // will not find `::foo`         // because `X::foo` hides it     } } 

This also applies to the name lookup in a base class:

class Base { public:     void foo(int); };  class Derived : public Base { public:     void foo();     void bar()     {         foo(42); // will not find `Base::foo`         // because `Derived::foo` hides it     } }; 

What is function overriding?

This is linked to the concept of virtual functions. [class.virtual]/2

If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.

class Base { private:     virtual void vf(int) const &&;     virtual void vf2(int);     virtual Base* vf3(int); };  class Derived : public Base { public: // accessibility doesn't matter!     void vf(int) const &&; // overrides `Base::vf(int) const &&`     void vf2(/*int*/);     // does NOT override `Base::vf2`     Derived* vf3(int);     // DOES override `Base::vf3` (covariant return type) }; 

The final overrider becomes relevant when calling a virtual function: [class.virtual]/2

A virtual member function C::vf of a class object S is a final overrider unless the most derived class of which S is a base class subobject (if any) declares or inherits another member function that overrides vf.

I.e. if you have an object of type S, the final overrider is the first overrider you see when traversing the class hierarchy of S back to its base classes. The important point is that the dynamic type of the function-call expression is used in order to determine the final overrider:

Base* p = new Derived; p -> vf(42);    // dynamic type of `*p` is `Derived`  Base& b = *p; b  . vf(42);    // dynamic type of `b` is `Derived` 

What is the difference between overriding and hiding?

Essentially, the functions in the base class are always hidden by functions of the same name in a derived class; no matter if the function in the derived class overrides a base class' virtual function or not:

class Base { private:     virtual void vf(int);     virtual void vf2(int); };  class Derived : public Base { public:     void vf();     // doesn't override, but hides `Base::vf(int)`     void vf2(int); // overrides and hides `Base::vf2(int)` }; 

To find a function name, the static type of an expression is used:

Derived d; d.vf(42);   // `vf` is found as `Derived::vf()`, this call is ill-formed             // (too many arguments) 

How do they relate to function overloads?

As "function hiding" is a form of name hiding, all overloads are affected if the name of a function is hidden:

class Base { private:     virtual void vf(int);     virtual void vf(double); };  class Derived : public Base { public:     void vf();     // hides `Base::vf(int)` and `Base::vf(double)` }; 

For function overriding, only the function in the base class with the same arguments will be overriden; you can of course overload a virtual function:

class Base { private:     virtual void vf(int);     virtual void vf(double);     void vf(char);  // will be hidden by overrides in a derived class };  class Derived : public Base { public:     void vf(int);    // overrides `Base::vf(int)`     void vf(double); // overrides `Base::vf(double)` }; 
like image 67
dyp Avatar answered Oct 05 '22 15:10

dyp


The difference between calling a virtual member function and calling a non-virtual member function is that, by definition, in the former case the target function is chosen in accordance with the dynamic type of the object expression used in the call, while in the latter case the static type is used.

That's all there is to it. Your example clearly illustrates this difference by p2->doA() and p2->doB() calls. Static type of *p2 expression is Parent, while dynamic type of the same expression is Child. This is why p2->doA() calls Parent::doA and p2->doB() calls Child::doB.

In contexts in which that difference matters, name hiding does not come into the picture at all.

like image 41
AnT Avatar answered Oct 05 '22 15:10

AnT