Inheritance
Inheritance#
Inheritance allows a class (subclass) to acquire properties and methods from another class (superclass). This enables code reuse and establishes "is-a" relationships between classes.
For example, an ElectricGuitar class can inherit from a Guitar class, meaning every electric guitar "is-a" guitar with all guitar characteristics plus electric-specific features.
Class Hierarchy#
The inheritance relationship creates a hierarchical structure where specialized classes extend the base class:
graph TD
A["Guitar<br/>(Base Class)"] --> B["ElectricGuitar"]
A --> C["AcousticGuitar"]
A --> D["ClassicalGuitar"]
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#fff3e0
style D fill:#fff3e0
Shared Properties and Methods#
The base class defines common attributes and behaviors that all subclasses inherit:
graph LR
A["Guitar Base Class"] --> B["brand: String"]
A --> C["model: String"]
A --> D["play() method"]
style A fill:#e3f2fd
style B fill:#c8e6c9
style C fill:#c8e6c9
style D fill:#c8e6c9
Specialized Features#
Each subclass adds its own unique properties and methods:
graph TD
A["ElectricGuitar"] --> B["pickupType: String"]
A --> C["distort() method"]
D["AcousticGuitar"] --> E["bodyShape: String"]
D --> F["fingerpick() method"]
G["ClassicalGuitar"] --> H["stringType: String"]
G --> I["pluck() method"]
style A fill:#fff3e0
style D fill:#fff3e0
style G fill:#fff3e0
Benefits of Inheritance:
- Code Reuse: Share common functionality across related classes
- Consistency: All subclasses behave predictably
- Maintainability: Changes to common behavior only need to be made in one place
Let's see how different programming languages implement inheritance:
Java uses the extends keyword for inheritance:
public class Guitar {
private String brand;
private String model;
public Guitar(String brand, String model) {
this.brand = brand;
this.model = model;
}
public void play() {
System.out.println("Playing the guitar!");
}
@Override
public String toString() {
return brand + " " + model;
}
}
public class ElectricGuitar extends Guitar {
private String pickupType;
public ElectricGuitar(String brand, String model, String pickupType) {
super(brand, model); // Calls the constructor of the superclass Guitar
this.pickupType = pickupType;
}
public void distort() {
System.out.println("Applying distortion!");
}
}
// Create an instance of ElectricGuitar
ElectricGuitar electricGuitar = new ElectricGuitar("Fender", "Stratocaster", "Single Coil");
electricGuitar.play(); // Output: Playing the guitar!
electricGuitar.distort(); // Output: Applying distortion!
System.out.println(electricGuitar); // Output: Fender Stratocaster
Kotlin uses the : symbol for inheritance:
open class Guitar(val brand: String, val model: String) {
open fun play() {
println("Playing the guitar!")
}
override fun toString(): String {
return "$brand $model";
}
}
class ElectricGuitar(brand: String, model: String, val pickupType: String) : Guitar(brand, model) {
fun distort() {
println("Applying distortion!");
}
}
// Create an instance of ElectricGuitar
val electricGuitar = ElectricGuitar("Fender", "Stratocaster", "Single Coil");
electricGuitar.play(); // Output: Playing the guitar!
electricGuitar.distort(); // Output: Applying distortion!
println(electricGuitar); // Output: Fender Stratocaster
TypeScript uses the extends keyword for inheritance:
class Guitar {
constructor(public brand: string, public model: string) {}
play() {
console.log("Playing the guitar!");
}
toString(): string {
return `${this.brand} ${this.model}`;
}
}
class ElectricGuitar extends Guitar {
constructor(brand: string, model: string, public pickupType: string) {
super(brand, model); // Calls the constructor of the superclass Guitar
}
distort() {
console.log("Applying distortion!");
}
}
// Create an instance of ElectricGuitar
const electricGuitar = new ElectricGuitar("Fender", "Stratocaster", "Single Coil");
electricGuitar.play(); // Output: Playing the guitar!
electricGuitar.distort(); // Output: Applying distortion!
console.log(electricGuitar.toString()); // Output: Fender Stratocaster
Dart uses the extends keyword for inheritance:
class Guitar {
String brand;
String model;
Guitar(this.brand, this.model);
void play() {
print("Playing the guitar!");
}
@override
String toString() {
return "$brand $model";
}
}
class ElectricGuitar extends Guitar {
String pickupType;
ElectricGuitar(String brand, String model, this.pickupType) : super(brand, model); // Calls the constructor of the superclass Guitar
void distort() {
print("Applying distortion!");
}
}
// Create an instance of ElectricGuitar
var electricGuitar = ElectricGuitar("Fender", "Stratocaster", "Single Coil");
electricGuitar.play(); // Output: Playing the guitar!
electricGuitar.distort(); // Output: Applying distortion!
print(electricGuitar); // Output: Fender Stratocaster
Swift uses the : symbol for inheritance:
class Guitar {
var brand: String
var model: String
init(brand: String, model: String) {
self.brand = brand
self.model = model
}
func play() {
print("Playing the guitar!")
}
var description: String {
return "\(brand) \(model)"
}
}
class ElectricGuitar: Guitar {
var pickupType: String
init(brand: String, model: String, pickupType: String) {
self.pickupType = pickupType;
super.init(brand: brand, model: model); // Calls the constructor of the superclass Guitar
}
func distort() {
print("Applying distortion!");
}
}
// Create an instance of ElectricGuitar
let electricGuitar = ElectricGuitar(brand: "Fender", model: "Stratocaster", pickupType: "Single Coil");
electricGuitar.play(); // Output: Playing the guitar!
electricGuitar.distort(); // Output: Applying distortion!
print(electricGuitar.description); // Output: Fender Stratocaster
Python uses parentheses for inheritance:
class Guitar:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def play(self):
print("Playing the guitar!")
def __str__(self):
return f"{self.brand} {self.model}"
class ElectricGuitar(Guitar):
def __init__(self, brand, model, pickup_type):
super().__init__(brand, model) # Calls the constructor of the superclass Guitar
self.pickup_type = pickup_type
def distort(self):
print("Applying distortion!")
# Create an instance of ElectricGuitar
electric_guitar = ElectricGuitar("Fender", "Stratocaster", "Single Coil");
electric_guitar.play(); # Output: Playing the guitar!
electric_guitar.distort(); # Output: Applying distortion!
print(electric_guitar); # Output: Fender Stratocaster