Virtual function/class, Where? Why? & How?
There is no doubt object-oriented languages are becoming the base for the creation of a new software stack. In this article, we are going to see the virtual function and its need for software design and development. Before getting into the conceptual understanding first we need to understand the problem or need for virtual function/class.
Inheritance is the characteristics where the derived class inherits the properties and characteristics of the Base class. Follow Below Example to understand the problem.
As we can see in the example "void no_fun()" function is overridden between the "Base" class and the "Derived" class. Function overriding means having the same signature of the function (same name and argument) in the "Base" and "Derived: class. In the example, the "Base" class and "Derived" class objects are created both objects are calling "no_fun()" function call, In this case, "obj_base" will invoke the base class function and "obj_dervied" will invoke the Derived class function(refer line no 19,20). this happens because at compile time compiler do early binding on the basis of the data type of the object. This works well until pointer handling comes into the picture.
In the same example Base class pointer "base_ptr" is created. Address of derived class object was stored in Base class pointer now If we call "no_fun" function it should invoke Derived class "no_fun" function but compiler do early/static binding based on its data type so Base class "no_void" function will be invoked(refer line no 22,24). This is the problem due to this we were unable to achieve run-time polymorphism. There is no doubt object-oriented languages are becoming the base for the creation of a new software stack. In this article, we are going to see the virtual function and its need for software design and development. Before getting into the conceptual understanding first we need to understand the problem or need for virtual function/class.
Inheritance is the characteristics where the derived class inherits the properties and characteristics of the Base class. Follow Below Example to understand the problem.
To understand the solution as well as the problem first we need to understand, what is early/static and late/dynamic binding?
Early/Static Binding: At compile time linking of the function call is done on the basis of data type object, this is called static/early binding which can be changed runtime. Due to this what problems may arrive that we saw in the above example.
Late/Dynamic Binding: In this case, the compiler creates dynamic links to the object and its function call which has the same function signature and preceded by the "virtual" keyword, this dynamic linking achieved by using the virtual pointer and virtual table. we will learn about virtual pointer and virtual table details below. Due to dynamic linking function calls are invoked on the basis of an address stored in it, unlike on its data type.
Virtual pointer & Virtual table
Virtual Pointer: Virtual pointer “v_ptr” will be created by the compiler after seeing the “virtual” keyword in the class. v_ptr is a private member of the class that will get inherited by the Derived class too. The virtual pointer is pointing to a virtual table.
Virtual table: virtual table is a static array that stores virtual function member addresses. It stores all the inherited and actual virtual function member addresses.
How Dynamic Linking happened?
A virtual pointer will be pointing to a virtual table. this table will have all virtual function entry/address. basic on what object/ pointer address is calling function, a particular offset will be added in virtual pointer this pointer will dereference the function call from table address. In this way, function calls are dynamically bounded by using the virtual pointer and virtual table. virtual table and virtual pointer are generated internally by compiler. To understand dynamic linking please refer to image and example.
In the Above class layout, we can see “v_ptr” created and it is pointing to the static virtual table. The static virtual table holds the address of all virtual functions in its scope. Non-virtual function entry is not made in this table. In over-ridden functions are defined with the virtual keywords so it will force the compiler to create dynamic links which result to virtual pointer and virtual table. This way dynamic linking happens. As we can see there is no fixed address that will be stored. The function call will happen on the address, not on the data type. All non-virtual functions will be statically bounded/linked.
After creating the Dynamic linking function call will now look like this, At compile time compiler manages this thing.
(*base_ptr->v_ptr[virtual_table_offset])();
Now let’s re-write the first example with the virtual keyword.
This time in Base we defined function as a virtual. In the derived class the same function will be treated as virtual only, writing virtually in the derived class is optional. This time when Base class pointer is holding the address of the derived class object and calls the function “no_fun”. Derived class function call only gets invoked this happened because of dynamic binding performed by the compiler. This greatly helps to achieve run time polymorphism in the code.
What we saw until now is a virtual function, the same way virtual class also used. The above picture indicates the diamond problem. Where “top” class properties are inherited by class right and class left now both the class holds properties of top class, the Bottom class is derived from class Left and class Right. Now in this scenario class Top properties are derived twice from two different classes which are not expected, to avoid this situation virtual class is used. Virtual keyword is preceded at the time of inheriting the parent class.
Software Engineer @ MBRDI | Ex-APTIV | Embedded C | C | C++ | Linux | Software | CAN | ADAS | AS&UX | Automotive .
4 年??