What Are the Differences Between Overriding Virtual Functions and Hiding Non-Virtual Functions

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

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)`
};

Difference between using non-virtual base class functions versus derived class non-implemented virtual functions

The flaw in your example is that you aren't using polymorphism. You operate on all the objects directly. You won't notice anything related to overriding, because none of the calls need to be resolved dynamically. And if the call is not resolved dynamically, there is absolutely no difference between virtual functions and non-virtual ones. To see the difference, use a helper free function:

void baz(A& a) {
a.foo();
a.bar();
a.xorp();
}

int main() {
// As before
baz(a);
baz(b);
baz(c);
}

Now you should be able to see a noticeable difference in how the calls to foo, bar and baz are resolved. In particular...

If I were to implement a xorp() in B, for example, it would effectively hide the A::xorp() and a call to b.xorp() would actually be a call to b.B::xorp().

... will no longer be true inside baz.

Is it okay to override (hide) a non-virtual method but still call it explicitly from a child class?

It's okay, but you're not overriding. You're hiding, as you already mentioned. Overriding means polymorphism will work on your object, and in your case, it won't.

For example:

A* a = new B;
a->foo();

will call the method A::foo(), whereas if you were to override the method (by making it virtual), it would call B::foo().

Also note that there might be issues related to the actual signature, for example if you had the method B::foo(int), you wouldn't be able to call foo(void) on a B object directly.

Difference between calling of virtual function and non virtual function?

Though virtualism/dynamic dispatch is strictly implementation defined, most(read all known) compilers implement it by using vptr and vtable.

Having said that, the difference between calling a non virtual function and virtual function is:

Non-virtual functions are resolved statically at Compile-time, While Virtual functions are resolved dynamically at Run-time.

In order to achieve this flexibility of being able to decide which function to call at run-time,
there is an little overhead in case of virtual functions.

An additional fetch call that needs to be performed and it is the overhead/price you pay for using dynamic dispatch.

In case of non-virtual function the sequence of calls is:

fetch-call

The compiler needs to fetch address of the function and then call it.

While in case of virtual functions the sequence is:

fetch-fetch-call

The compiler needs to fetch the vptr from the this, then fetch the address of the function from the vptr and then call the function.

This is just a simplified explanation the actual sequence maybe far more complex than this but this is what you really need to know, One does not really need to know the implementation nitty gritty's.

Good Read:

Inheritance & Virtual Functions

C++ Virtual Void vs no virtual

If a function is virtual, the call is dynamically dispatched to the implementation provided by the derived type through the vtable at runtime, whereas without, the compiler looks at the object at compile time and selects the class-method of the static type. If you have a pointer to the base-class this means that the base-implementation is used, if the function is not virtual:

Enemy *e = new Minion(); e->attack();

will print "Attack Enemy!" if attack is not virtual. When using a virtual function, the compiler will insert some logic to lookup the right implementation at run-time, and, when e->attack() gets executed, look up the implementation in the vtable of the object pointer to by e, finding that Minion overrides attack, and thus printing "Attack Minion!".

If you want to force your derived classes to override the base-class method you can also make the function purely virtual by using

virtual void attack() = 0;

Overriding vs Virtual

This is the classic question of how polymorphism works I think. The main idea is that you want to abstract the specific type for each object. In other words: You want to be able to call the Child instances without knowing it's a child!

Here is an example:
Assuming you have class "Child" and class "Child2" and "Child3" you want to be able to refer to them through their base class (Parent).

Parent* parents[3];
parents[0] = new Child();
parents[1] = new Child2();
parents[2] = new Child3();

for (int i=0; i<3; ++i)
parents[i]->say();

As you can imagine, this is very powerful. It lets you extend the Parent as many times as you want and functions that take a Parent pointer will still work. For this to work as others mention you need to declare the method as virtual.

C++ override specifier without virtual? Does override imply virtual?

The answer you're looking for is in https://en.cppreference.com/w/cpp/language/virtual

If some member function vf is declared as virtual in a class Base, and some class Derived, which is derived, directly or indirectly, from Base, has a declaration for member function with the same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).

Overriding non-virtual methods

Yep, you are misunderstanding a little.

The method of the same name on the derived class will hide the parent method in this case. You would imagine that if this weren't the case, trying to create a method with the same name as a base class non-virtual method should throw an error. It is allowed and it's not a problem - and if you call the method directly as you have done it will be called fine.

But, being non-virtual, C++ method lookup mechanisms that allow for polymorphism won't be used. 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.

For example, try adding these lines:

Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

...and observe the output as expected:

Base: Non-virtual display.

Base: Virtual display.

Base: Non-virtual display.
Derived: Virtual display.

Virtual function calling a non-virtual function and vice versa

Calls to your non-virtual abc function are resolved, effectively, at compile time: so, when that is called from within another member function of class B, the class B version of the function is called, and is passed a pointer (this) to the object from which it is being called; similarly, if called from within a class A function, then the class A definition will be used. That is to say, to the compiler, non-virtual functions associate with a class, rather than any particular instance of the class.

However, your virtual xyz function is handled differently by the compiler; in this case, a reference or pointer to the function is added to the class definition (this is generally added into what is known as a vtable, although the details are implementation-specific); when any objects of your class(es) are created, they include a copy of that function pointer and/or vtable. When the compiler sees code to call such a virtual function, it translates that into a call via the appropriate function pointer; so, the function 'travels with' the actual object: whether the function is called from the derived class or base class (in your code) is irrelevant – the function called is the one belonging to the object (instance) from which it is invoked.

In summary: calls to non-virtual functions are resolved at compile time, whereas calls to virtual functions are (conceptually) resolved at run time.

To see creation of this "vtable" in action, try compiling and running the following code:

#include <iostream>

class A {
public:
int i;
~A() = default;
void foo() { std::cout << i << std::endl; }
};

class B {
public:
int i;
virtual ~B() = default;
virtual void foo() { std::cout << i << std::endl; }
};

int main()
{
std::cout << sizeof(A) << std::endl;
std::cout << sizeof(B) << std::endl;
return 0;
}

The only difference between the two classes is that one has virtual functions and the other doesn't – yet that causes a significant difference in the size of class objects: the size of the vtable (with, possibly, some 'padding' for optimal alingment of data)! (On my 64-bit Windows, using MSVC, I get sizes of 4 and 16, but the actual values will vary between compilers and platforms.)



Related Topics



Leave a reply



Submit