|
Virtual Functions
The virtual keyword is the function specifier, which provides a mechanism to select dynamically at runtime an appropriate function-member among the functions of basic and derived classes. Structures cannot have virtual functions. It can be used to change the declarations for function-members only.
The virtual function, like an ordinary function, must have an executable body. When called, its semantic is the same as that of other functions.
A virtual function may be overridden in a derived class. The choice of what function definition should be called for a virtual function is made dynamically (at runtime). A typical case is when a base class contains a virtual function, and derived classes have their own versions of this function.
The pointer to the base class can indicate either a base class object or the object of a derived class. The choice of the member-function to call will be performed at runtime and will depend on the type of the object, not the type of the pointer. If there is no member of a derived type, the virtual function of the base class is used by default.
Destructors are always virtual, regardless of whether they are declared with the virtual keyword or not.
Let's consider the use of virtual functions on the example of MT5_Tetris.mq5. The base class CTetrisShape with the virtual function Draw is defined in the included file MT5_TetrisShape.mqh.
//+------------------------------------------------------------------+
|
Further, for each derived class, this function is implemented in accordance with characteristics of a descendant class. For example, the first shape CTetrisShape1 has its own implementation of the Draw() function:
class CTetrisShape1 : public CTetrisShape
|
The Square shape is described by class CTetrisShape6 and has its own implementation of the Draw() method:
class CTetrisShape6 : public CTetrisShape
|
Depending on the class, to which the created object belongs, it calls the virtual function of this or that derived class.
void CTetrisField::NewShape()
|
The 'override' modifier means that the declared function must override the method of a parent class. Use of this method allows you to avoid overriding errors, for example it allows you to avoid accidental modification of the method signature. Suppose, the 'func' method is defined in the base class. The method accepts an int variable as an argument:
class CFoo |
Next, the method is overridden in the child class:
class CBar : public CFoo |
However, the argument type is mistakenly changed from int to short. In fact, this is not method overriding, but it is method overloading. Acting in accordance with the overloaded function defining algorithm, the compiler can in certain situations choose a method defined in the base class instead of the overridden method.
In order to avoid such errors, you should explicitly add the 'override' modifier to the method you want to override.
class CBar : public CFoo |
If the method signature is changed during overriding, the compiler will not be able to find a method with the same signature in the parent class, and it will return a compilation error:
'CBar::func' method is declared with 'override' specifier but does not override any base class method |
The 'final' modifier does the opposite — it prohibits method overriding in child classes. If a method implementation is sufficient and fully complete, declare this method with the 'final' modifier so as to make sure that it will not be modified later.
class CFoo |
If you try to override a method with the 'final' modifier as shown in the above example, the compiler will return an error:
'CFoo::func' method declared as 'final' cannot be overridden by 'CBar::func' |
See also