Final Keyword in C++
What is C++'s final keyword?
The 'final' keyword in C++ is used to enforce immutability and stop classes and virtual functions from being further descended from or overridden. When used on a class, it prevents that class from being the terminal class in the inheritance hierarchy, preventing any other class from deriving from it. When you want to design a class that shouldn't be further specialised or extended, this is quite helpful. The 'final' keyword also prohibits derived classes from overriding virtual functions when used, guaranteeing ensuring the base class's version is maintained across the inheritance chain. The 'final' keyword encourages code security along with transparency by specifying the immutability of specific classes and functions.
The purpose of the final keyword in C++:
To prevent further inheritance and overriding of classes and virtual functions in C++, use the final keyword. A class becomes the terminal class in the inheritance tree when it is declared as final since it cannot be utilised as a base class. This makes sure that no other class can specialise or expand the class in any way. The final keyword, when used on a virtual function, prevents derived classes from overriding that function, ensuring that the implementation of the base class is preserved across the inheritance chain.
The main justifications for using the last keyword are:
- Immutability: It enables you to specify which classes or functions shouldn't be altered or expanded, enhancing the security and stability of your code.
- Design Clarity: It makes the design and intent of the code more explicit by clearly indicating the intention to forbid additional inheritance or overriding.
- Code Optimisation: By defining final, the compiler may be able to increase the efficiency of virtual function calls since it is aware that the function cannot be altered.
But it's crucial to utilise final sparingly. The overuse of final might result in unnecessarily restrictive designs that make it difficult to maintain and extend the code. The final keyword should only be used when it is specifically necessary to stop further modification and when it is consistent with the software's general design objectives.
Syntax of final keyword
Whether it is used for classes or virtual functions determines the syntax of the final keyword in C++.
Final Class: Use the final keyword following the class declaration to designate a class as final and disallow any further derivation from it.
class Base {
// ...
};
class Derived final : public Base {
// ...
};
Derived is a class that was descended from Base in our example. We signal that Derived cannot be further subclassed by using final.
Virtual Function Marked as Final: Use the final keyword following the virtual function declaration to designate a virtual function as final and prevent it from being overridden in derived classes:
class Base {
public:
virtual void someFunction() final {
// Implementation of the function.
}
};
class Derived : public Base {
public:
// Error: Cannot override final function 'someFunction'.
// void someFunction() override {
// // New implementation for the function.
// }
};
Example 1
#include <iostream>
class Base {
public:
virtual void someFunction() {
std::cout << "Base::someFunction()" << std::endl;
}
};
class Derived final : public Base {
public:
void someFunction() override {
std::cout << "Derived::someFunction()" << std::endl;
}
};
int main() {
Base* basePtr = new Derived();
basePtr->someFunction();
delete basePtr;
return 0;
}
Output
Explanation
As an illustration, consider the basic class basic, which has the virtual function someFunction(). The Derived class is designated as final, preventing further derivation of it. A compilation error would occur if you tried to derive another class from Derived.
When we establish a pointer of type Base* pointing to an instance of Derived, the overridden function in Derived gets invoked at runtime. The Derived class overrides the virtual function someFunction().
Please take note that the code's commented parts are there to highlight the mistakes that can happen when attempting to derive from a final class. The compilation errors noted in the comments will be triggered by uncommenting certain parts.
Example 2
#include <iostream>
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a shape." << std::endl;
}
};
class Circle : public Shape {
public:
void draw() final {
std::cout << "Drawing a circle." << std::endl;
}
};
int main() {
Shape* shapePtr = new Circle();
shapePtr->draw();
delete shapePtr;
return 0;
}
Output
Explanation
In this illustration, the basic class Shape has a virtual function called draw(). The virtual function draw() in the Circle class, which derives from Shape, is tagged as final.
There would be a compilation issue if you tried to derive another class, like SmallCircle, from Circle and override the draw() function. This effort and the
error that results from attempting to override a last virtual function are displayed in the commented portion of the code.
When a pointer of type Shape* that points to an instance of Circle is created at runtime, the overridden method in Circle is called.
A effective technique to establish essential functionality inside a class hierarchy while preventing future alteration in particular areas of the codebase is to utilise the final keyword, which helps ensure that the behaviour of some virtual functions remains intact.