C++11 Override Keyword
Table of Contents
- What is the Override Keyword?
- The Problem Without Override
- The Solution: Using Override Keyword
- Benefits of Override Keyword
- Best Practices
What is the Override Keyword?
The override keyword is a C++11 feature that explicitly indicates that a member function in a derived class is intended to override a virtual function from the base class. It provides compile-time checking to ensure the override is valid.
The override keyword is placed after the function signature in a derived class to explicitly declare that the function overrides a virtual function from the base class.
Syntax:
class Base {
public:
virtual void functionName() {
// base implementation
}
};
class Derived : public Base {
public:
void functionName() override { // Explicitly marks as override
// derived implementation
}
};
The Problem Without Override
Without the override keyword, subtle mistakes in function signatures can lead to bugs that are difficult to detect. The compiler won’t warn you if you accidentally create a new function instead of overriding the base class function.
Example 1: Typo in Function Name
#include <iostream>
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a shape" << std::endl;
}
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
void darw() { // Typo: 'darw' instead of 'draw'
std::cout << "Drawing a circle" << std::endl;
}
};
int main() {
Shape* shape = new Circle();
shape->draw(); // Calls Shape::draw(), not Circle::darw()
delete shape;
return 0;
}
Output:
Drawing a shape
Problem: The typo darw() creates a new function instead of overriding draw(). The compiler doesn’t warn you, and the base class function is called instead of the derived class function.
Example 2: Wrong Parameter Types
#include <iostream>
class Animal {
public:
virtual void makeSound(int volume) {
std::cout << "Animal sound at volume " << volume << std::endl;
}
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void makeSound(double volume) { // Wrong parameter type: double instead of int
std::cout << "Woof at volume " << volume << std::endl;
}
};
int main() {
Animal* animal = new Dog();
animal->makeSound(5); // Calls Animal::makeSound(int), not Dog::makeSound(double)
delete animal;
return 0;
}
Output:
Animal sound at volume 5
Problem: The parameter type doesn’t match (double vs int), so this creates a new function instead of overriding. The base class function is called.
Example 3: Missing const Qualifier
#include <iostream>
class Vehicle {
public:
virtual void getInfo() const {
std::cout << "Vehicle info" << std::endl;
}
virtual ~Vehicle() = default;
};
class Car : public Vehicle {
public:
void getInfo() { // Missing 'const' qualifier
std::cout << "Car info" << std::endl;
}
};
int main() {
Vehicle* vehicle = new Car();
vehicle->getInfo(); // Calls Vehicle::getInfo(), not Car::getInfo()
delete vehicle;
return 0;
}
Output:
Vehicle info
Problem: Missing const qualifier means the signature doesn’t match, creating a new function instead of overriding.
The Solution: Using Override Keyword
Correct Usage
#include <iostream>
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a shape" << std::endl;
}
virtual void area() const {
std::cout << "Calculating shape area" << std::endl;
}
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
void draw() override { // Correctly overrides Shape::draw()
std::cout << "Drawing a circle" << std::endl;
}
void area() const override { // Correctly overrides Shape::area()
std::cout << "Calculating circle area" << std::endl;
}
};
int main() {
Shape* shape = new Circle();
shape->draw(); // Calls Circle::draw()
shape->area(); // Calls Circle::area()
delete shape;
return 0;
}
Output:
Drawing a circle
Calculating circle area
Success: The derived class functions are correctly called because they properly override the base class functions.
Catching Errors at Compile Time
Example 1: Typo Caught by Override
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a shape" << std::endl;
}
};
class Circle : public Shape {
public:
void darw() override { // Compilation Error!
std::cout << "Drawing a circle" << std::endl;
}
};
Compiler Error:
error: 'void Circle::darw()' marked 'override', but does not override
Example 2: Wrong Parameter Type Caught
class Animal {
public:
virtual void makeSound(int volume) {
std::cout << "Animal sound" << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound(double volume) override { // Compilation Error!
std::cout << "Woof" << std::endl;
}
};
Compiler Error:
error: 'void Dog::makeSound(double)' marked 'override', but does not override
Example 3: Missing const Caught
class Vehicle {
public:
virtual void getInfo() const {
std::cout << "Vehicle info" << std::endl;
}
};
class Car : public Vehicle {
public:
void getInfo() override { // Compilation Error!
std::cout << "Car info" << std::endl;
}
};
Compiler Error:
error: 'void Car::getInfo()' marked 'override', but does not override
Benefits of Override Keyword
- Compile-time Error Detection: Catches mistakes early when the function signature doesn’t match the base class
- Self-documenting Code: Makes it clear that a function is intended to override a base class function
- Refactoring Safety: If the base class function signature changes, the compiler will catch all derived classes that need updating
- Prevents Silent Bugs: Eliminates bugs caused by accidentally creating new functions instead of overriding
- Better Code Maintenance: Easier to understand class hierarchies and relationships
- No Runtime Overhead: It’s a compile-time feature with zero runtime cost
Best Practices
- Always use
overridewhen you intend to override a virtual function - Use
virtualonly in base classes for the initial declaration - Don’t use both
virtualandoverridein derived classes (redundant) - Mark base class destructors as
virtualwhen using inheritance - Consider using
finalto prevent further overriding if needed
Example of Best Practices:
class Base {
public:
virtual void foo() { }
virtual void bar() { }
virtual ~Base() = default; // Virtual destructor
};
class Derived : public Base {
public:
void foo() override { } // Good: uses override
void bar() override final { } // Good: override and prevent further overriding
};
class FurtherDerived : public Derived {
public:
void foo() override { } // Good: overrides Derived::foo()
// void bar() override { } // Error: bar is final in Derived
};