This lesson was translated automatically – it may contain errors.
Introduction
Classes rarely live alone. Write a few of them and you find that half of their code is the
same: an employee, a customer and a courier all have a name and a phone number; every document
has an author and a creation date; every shape on a canvas has coordinates and a draw
method. Copying that into each class means later hunting through the whole project for the
other places the same logic sits in.
Hence the natural wish to build a hierarchy: describe the common part once and add the
differences on top. In an online shop that is Product, with Book, Clothing and
Electronics below it: price, name and discount are described in one place, while size,
author and warranty belong to their own kind of product. That is where inheritance comes
from.
Definition: inheritance lets a class take over the attributes and methods of another class, building new classes by abstracting out the common properties.
The class being inherited from is called the parent (the parent or base class), and the
one that inherits is the child (the child class, the subclass). In the shop example
Product is the parent, and Book, Clothing and Electronics are its children.
Vehicle: drive, open the doors, turn on the headlights.Truck: adds loading gravel and unhitching a trailer, but inherits everything fromVehicle.
An example
using System;
public class Vehicle
{
public int Weight { get; set; }
public int Length { get; set; }
public bool IsHeadlightsOn { get; set; }
public Vehicle()
{
Weight = 100;
Length = 120;
IsHeadlightsOn = false;
}
public void TurnOnHeadlights()
{
IsHeadlightsOn = true;
}
}
public class Truck : Vehicle
{
public bool IsLoaded { get; set; }
public Truck()
{
IsLoaded = true;
}
public void Unload()
{
IsLoaded = false;
}
}
class Program
{
static void Main()
{
Truck car = new Truck();
// The method is declared in Vehicle, but the truck can turn on the headlights too
car.TurnOnHeadlights();
Console.WriteLine(car.IsHeadlightsOn);
// And this one is the truck's own method
car.Unload();
Console.WriteLine(car.IsLoaded);
}
}
#include <iostream>
class Vehicle {
public:
int weight = 100;
int length = 120;
bool is_headlights_on = false;
void TurnOnHeadlights() { is_headlights_on = true; }
};
// Inheritance in C++ comes as public, protected and private –
// public is the one that means «is a»
class Truck : public Vehicle {
public:
bool is_loaded = true;
void Unload() { is_loaded = false; }
};
int main() {
Truck car;
// The method is declared in Vehicle, but the truck can turn on the headlights too
car.TurnOnHeadlights();
std::cout << car.is_headlights_on << std::endl;
// And this one is the truck's own method
car.Unload();
std::cout << car.is_loaded << std::endl;
return 0;
}
package main
import "fmt"
// Go has no inheritance – it has embedding instead.
// Truck gets the fields and methods of Vehicle, but that is composition, not a hierarchy.
type Vehicle struct {
Weight int
Length int
IsHeadlightsOn bool
}
func NewVehicle() Vehicle {
return Vehicle{Weight: 100, Length: 120}
}
func (v *Vehicle) TurnOnHeadlights() {
v.IsHeadlightsOn = true
}
type Truck struct {
Vehicle
IsLoaded bool
}
func NewTruck() *Truck {
return &Truck{Vehicle: NewVehicle(), IsLoaded: true}
}
func (t *Truck) Unload() {
t.IsLoaded = false
}
func main() {
car := NewTruck()
// The method belongs to Vehicle but is called on the truck: embedding
// lifts it up as if it were declared on Truck
car.TurnOnHeadlights()
fmt.Println(car.IsHeadlightsOn)
// And this one is the truck's own method
car.Unload()
fmt.Println(car.IsLoaded)
}
class Vehicle:
def __init__(self):
self.weight = 100
self.length = 120
self.is_headlights_on = False
def turn_on_headlights(self):
self.is_headlights_on = True
class Truck(Vehicle):
def __init__(self):
super().__init__()
self.is_loaded = True
def unload(self):
self.is_loaded = False
if __name__ == "__main__":
car = Truck()
# The method is declared in Vehicle, but the truck can turn on the headlights too
car.turn_on_headlights()
print(car.is_headlights_on)
# And this one is the truck's own method
car.unload()
print(car.is_loaded)
class Vehicle {
weight = 100;
length = 120;
isHeadlightsOn = false;
turnOnHeadlights(): void {
this.isHeadlightsOn = true;
}
}
class Truck extends Vehicle {
isLoaded = true;
unload(): void {
this.isLoaded = false;
}
}
const car = new Truck();
// The method is declared in Vehicle, but the truck can turn on the headlights too
car.turnOnHeadlights();
console.log(car.isHeadlightsOn);
// And this one is the truck's own method
car.unload();
console.log(car.isLoaded);
public class Vehicle {
private int weight;
private int length;
private boolean isHeadlightsOn;
public Vehicle() {
weight = 100;
length = 120;
isHeadlightsOn = false;
}
public boolean isHeadlightsOn() {
return isHeadlightsOn;
}
public void turnOnHeadlights() {
isHeadlightsOn = true;
}
}
public class Truck extends Vehicle {
private boolean isLoaded;
public Truck() {
isLoaded = true;
}
public boolean isLoaded() {
return isLoaded;
}
public void unload() {
isLoaded = false;
}
}
public class Program {
public static void main(String[] args) {
Truck car = new Truck();
// The method is declared in Vehicle, but the truck can turn on the headlights too
car.turnOnHeadlights();
System.out.println(car.isHeadlightsOn());
// And this one is the truck's own method
car.unload();
System.out.println(car.isLoaded());
}
}
// In Kotlin classes are closed for inheritance by default:
// Vehicle needs the open modifier before anything can inherit from it.
open class Vehicle {
var weight = 100
var length = 120
var isHeadlightsOn = false
fun turnOnHeadlights() {
isHeadlightsOn = true
}
}
class Truck : Vehicle() {
var isLoaded = true
fun unload() {
isLoaded = false
}
}
fun main() {
val car = Truck()
// The method is declared in Vehicle, but the truck can turn on the headlights too
car.turnOnHeadlights()
println(car.isHeadlightsOn)
// And this one is the truck's own method
car.unload()
println(car.isLoaded)
}
What inheritance gives you
The main benefit of inheritance is describing complex logic once. Write an encryption
algorithm once in the base class Device and every subclass, from a smart watch to a router,
gets it ready-made. Each adds its own part: the watch measures the pulse, the router shares
the network, and the encryption is one and the same for all of them, in one place.
Hence the practical effect: a fix in the base class reaches every subclass at once. Found a bug in the algorithm – you fix it once instead of in fifteen gadgets.
It sounds as though the mechanism is good without reservation. But look at the example above once more: Go has no inheritance at all – it has embedding, which is composition. And Go is no exception here; younger languages drop class inheritance one after another. Why something that looks so convenient turned out to be so contested is the subject of the next lesson.