1. php
  2. /object oriented
  3. /inheritance

PHP Inheritance

Introduction to PHP Inheritance

Inheritance is one of the fundamental pillars of Object-Oriented Programming (OOP), alongside encapsulation and polymorphism. At its core, inheritance allows developers to create new classes based on existing ones, establishing an "is-a" relationship between parent and child classes.

Think of inheritance like a biological family tree or organizational hierarchy. Just as children inherit traits from their parents while developing their own unique characteristics, classes in programming can inherit properties and behaviors from parent classes while adding or modifying functionality to suit their specific needs.

Why Inheritance Matters in Software Design

Code Reusability: Rather than duplicating common functionality across multiple classes, inheritance allows you to write code once in a parent class and reuse it in multiple child classes. This reduces development time and maintenance overhead.

Hierarchical Organization: Inheritance naturally models real-world hierarchical relationships. For example, in an e-commerce system, you might have a base Product class with common properties, and specialized classes like Book, Electronics, and Clothing that inherit from it while adding their own specific features.

Consistency and Standards: When multiple classes inherit from the same parent, they share a common interface and behavior patterns. This creates consistency across your application and makes it easier for other developers to understand and work with your code.

Polymorphism Foundation: Inheritance enables polymorphism, allowing objects of different classes to be treated uniformly through their common parent interface. This is crucial for building flexible, extensible systems.

Maintenance and Evolution: When you need to add functionality or fix bugs in common behavior, you can do it once in the parent class rather than updating every individual class. This reduces the risk of inconsistencies and makes your codebase more maintainable.

Understanding the "Is-A" Relationship

The key to successful inheritance design is understanding the "is-a" relationship. Inheritance should only be used when the child class truly "is a" specialized version of the parent class:

  • A Car is a Vehicle
  • A Manager is an Employee
  • A Dog is an Animal
  • A House is an Address ✗ (has-a relationship, use composition instead)

When this relationship doesn't hold true, inheritance becomes forced and unnatural, leading to confusing code and design problems down the road.

Inheritance vs. Composition: Making the Right Choice

While inheritance is powerful, it's not always the best solution. Understanding when to use inheritance versus composition is crucial for good design:

Use Inheritance When:

  • There's a clear "is-a" relationship
  • Child classes are specialized versions of the parent
  • You want to leverage polymorphism
  • The parent class represents a fundamental concept that won't change drastically

Use Composition When:

  • There's a "has-a" relationship
  • You need multiple inheritance-like behavior (PHP only supports single inheritance)
  • The relationship between classes might change over time
  • You want more flexible, loosely-coupled design

Core Inheritance Concepts

Method Overriding: Child classes can replace parent methods with their own implementations. This allows for specialized behavior while maintaining the same interface.

Method Extension: Child classes can extend parent methods by calling the parent implementation and adding additional functionality.

Visibility Control: PHP's public, protected, and private visibility levels control how inherited members can be accessed.

Abstract Classes: Define incomplete classes that serve as blueprints for child classes, enforcing certain methods while providing common functionality.

PHP supports single inheritance, meaning a child class can inherit from only one parent class directly, but it can create inheritance chains where multiple levels of inheritance exist.

Real-World Design Patterns with Inheritance

Template Method Pattern

The Template Method pattern is one of the most practical applications of inheritance. It defines the skeleton of an algorithm in a parent class, with child classes implementing specific steps. This ensures algorithmic consistency while allowing customization.

For example, consider a data processing system where the overall process (validate → transform → save → cleanup) remains the same, but each step's implementation varies depending on the data type (CSV, JSON, XML).

Strategy Pattern vs. Inheritance

While inheritance can implement the Strategy pattern, it's not always the best choice. The Strategy pattern using composition often provides more flexibility, especially when strategies need to be changed at runtime or when you need multiple strategy types simultaneously.

Understanding when inheritance serves the Strategy pattern well and when composition is better helps you make informed design decisions.

Common Inheritance Pitfalls and How to Avoid Them

The Deep Inheritance Trap

Deep inheritance hierarchies (more than 3-4 levels) often indicate design problems. They become difficult to understand, maintain, and extend. Each level adds complexity and coupling, making the system fragile.

Solution: Favor composition over inheritance, use interfaces to define contracts, and keep inheritance hierarchies shallow and focused.

The Fragile Base Class Problem

When parent classes change, they can break child classes in unexpected ways. This is especially problematic in large systems where the inheritance hierarchy spans multiple teams or modules.

Solution: Design base classes carefully, use semantic versioning, provide clear contracts through interfaces, and minimize breaking changes.

Inappropriate Inheritance

Using inheritance for code reuse alone, without a true "is-a" relationship, leads to confusing and brittle designs. This often happens when developers focus on avoiding code duplication without considering the logical relationship between classes.

Solution: Always validate the "is-a" relationship. If it doesn't exist naturally, use composition, traits, or utility classes instead.

The Yo-Yo Problem

In complex inheritance hierarchies, understanding the flow of execution can become like following a yo-yo string up and down the hierarchy. Method calls bounce between parent and child classes, making debugging and maintenance difficult.

Solution: Keep method overriding focused and logical. Use clear naming conventions and documentation to indicate the inheritance flow.

Practical Implementation Guidelines

Designing for Extension

When creating classes that will be inherited, design them with extension in mind:

  • Use protected visibility for methods and properties that subclasses might need
  • Provide hook methods that subclasses can override for customization
  • Keep the parent class focused on core functionality
  • Document the intended inheritance patterns and constraints

Method Naming Conventions

Establish clear naming conventions for inherited hierarchies:

  • Use descriptive names that indicate the method's purpose
  • Prefix template methods or hooks appropriately
  • Avoid generic names that might conflict across the hierarchy

Testing Inheritance Hierarchies

Testing inherited classes requires special consideration:

  • Test the parent class independently
  • Test each child class's specific functionality
  • Verify that polymorphic behavior works correctly
  • Test edge cases where parent and child behavior interact

The Liskov Substitution Principle

This principle states that objects of a superclass should be replaceable with objects of a subclass without breaking the application. When overriding methods:

  • Accept the same or more general parameters
  • Return the same or more specific types
  • Don't throw additional exceptions that the parent doesn't throw
  • Maintain the same logical behavior contract

Now let's explore these concepts through practical PHP implementations:

Basic Inheritance Syntax

Extending a Class

<?php
class ParentClass {
    protected $property;
    
    public function parentMethod() {
        return "This is from the parent class";
    }
}

class ChildClass extends ParentClass {
    public function childMethod() {
        return "This is from the child class";
    }
    
    public function accessParentProperty() {
        return $this->property; // Can access protected parent properties
    }
}

$child = new ChildClass();
echo $child->parentMethod(); // Output: This is from the parent class
echo $child->childMethod();  // Output: This is from the child class
?>

Real-World Inheritance Example

Vehicle Hierarchy

<?php
abstract class Vehicle {
    protected $brand;
    protected $model;
    protected $year;
    protected $engineStatus = false;
    
    public function __construct($brand, $model, $year) {
        $this->brand = $brand;
        $this->model = $model;
        $this->year = $year;
    }
    
    public function startEngine() {
        $this->engineStatus = true;
        return "Engine started for {$this->year} {$this->brand} {$this->model}";
    }
    
    public function stopEngine() {
        $this->engineStatus = false;
        return "Engine stopped";
    }
    
    public function getInfo() {
        return "{$this->year} {$this->brand} {$this->model}";
    }
    
    // Abstract method - must be implemented by child classes
    abstract public function getMaxSpeed();
    abstract public function getFuelType();
}

class Car extends Vehicle {
    private $doors;
    private $transmission;
    
    public function __construct($brand, $model, $year, $doors = 4, $transmission = 'automatic') {
        parent::__construct($brand, $model, $year);
        $this->doors = $doors;
        $this->transmission = $transmission;
    }
    
    public function getMaxSpeed() {
        return "180 km/h"; // Typical car max speed
    }
    
    public function getFuelType() {
        return "Gasoline";
    }
    
    public function honk() {
        return "Beep beep!";
    }
    
    public function getCarDetails() {
        return $this->getInfo() . " - {$this->doors} doors, {$this->transmission} transmission";
    }
}

class Motorcycle extends Vehicle {
    private $type;
    
    public function __construct($brand, $model, $year, $type = 'standard') {
        parent::__construct($brand, $model, $year);
        $this->type = $type;
    }
    
    public function getMaxSpeed() {
        return "200 km/h"; // Motorcycles typically faster
    }
    
    public function getFuelType() {
        return "Gasoline";
    }
    
    public function wheelie() {
        return "Performing a wheelie!";
    }
    
    public function getMotorcycleDetails() {
        return $this->getInfo() . " - {$this->type} type";
    }
}

// Usage
$car = new Car("Toyota", "Camry", 2023, 4, "automatic");
echo $car->startEngine(); // Output: Engine started for 2023 Toyota Camry
echo $car->getCarDetails(); // Output: 2023 Toyota Camry - 4 doors, automatic transmission
echo $car->honk(); // Output: Beep beep!

$motorcycle = new Motorcycle("Yamaha", "R6", 2023, "sport");
echo $motorcycle->getMotorcycleDetails(); // Output: 2023 Yamaha R6 - sport type
echo $motorcycle->wheelie(); // Output: Performing a wheelie!
?>

Method Overriding

Child classes can override parent methods to provide specialized behavior:

<?php
class Animal {
    protected $name;
    protected $species;
    
    public function __construct($name, $species) {
        $this->name = $name;
        $this->species = $species;
    }
    
    public function makeSound() {
        return "{$this->name} makes a generic animal sound";
    }
    
    public function sleep() {
        return "{$this->name} is sleeping";
    }
    
    public function getInfo() {
        return "{$this->name} is a {$this->species}";
    }
}

class Dog extends Animal {
    private $breed;
    
    public function __construct($name, $breed) {
        parent::__construct($name, "Dog");
        $this->breed = $breed;
    }
    
    // Override parent method
    public function makeSound() {
        return "{$this->name} barks: Woof! Woof!";
    }
    
    // Add dog-specific behavior
    public function fetch() {
        return "{$this->name} is fetching the ball";
    }
    
    public function wagTail() {
        return "{$this->name} is wagging their tail happily";
    }
    
    // Override to include breed information
    public function getInfo() {
        return "{$this->name} is a {$this->breed} {$this->species}";
    }
}

class Cat extends Animal {
    private $color;
    
    public function __construct($name, $color) {
        parent::__construct($name, "Cat");
        $this->color = $color;
    }
    
    // Override parent method
    public function makeSound() {
        return "{$this->name} meows: Meow!";
    }
    
    // Add cat-specific behavior
    public function purr() {
        return "{$this->name} is purring contentedly";
    }
    
    public function scratch() {
        return "{$this->name} is scratching the furniture";
    }
    
    public function getInfo() {
        return "{$this->name} is a {$this->color} {$this->species}";
    }
}

// Usage
$dog = new Dog("Buddy", "Golden Retriever");
echo $dog->makeSound(); // Output: Buddy barks: Woof! Woof!
echo $dog->fetch(); // Output: Buddy is fetching the ball
echo $dog->getInfo(); // Output: Buddy is a Golden Retriever Dog

$cat = new Cat("Whiskers", "orange");
echo $cat->makeSound(); // Output: Whiskers meows: Meow!
echo $cat->purr(); // Output: Whiskers is purring contentedly
echo $cat->getInfo(); // Output: Whiskers is a orange Cat
?>

Using the parent Keyword

The parent keyword allows access to parent class methods and properties:

<?php
class Employee {
    protected $name;
    protected $salary;
    protected $department;
    
    public function __construct($name, $salary, $department) {
        $this->name = $name;
        $this->salary = $salary;
        $this->department = $department;
    }
    
    public function getDetails() {
        return "Employee: {$this->name}, Salary: $" . number_format($this->salary);
    }
    
    public function calculateBonus() {
        return $this->salary * 0.05; // 5% bonus
    }
    
    public function work() {
        return "{$this->name} is working in {$this->department}";
    }
}

class Manager extends Employee {
    private $teamSize;
    private $projects;
    
    public function __construct($name, $salary, $department, $teamSize) {
        parent::__construct($name, $salary, $department);
        $this->teamSize = $teamSize;
        $this->projects = [];
    }
    
    // Override to include management details
    public function getDetails() {
        $baseDetails = parent::getDetails();
        return $baseDetails . ", Team Size: {$this->teamSize}, Role: Manager";
    }
    
    // Override bonus calculation for managers
    public function calculateBonus() {
        $baseBonus = parent::calculateBonus();
        $managementBonus = $this->teamSize * 500; // $500 per team member
        return $baseBonus + $managementBonus;
    }
    
    public function assignProject($project) {
        $this->projects[] = $project;
        return "Project '{$project}' assigned to {$this->name}'s team";
    }
    
    public function conductMeeting() {
        return "{$this->name} is conducting a team meeting";
    }
    
    // Override work method
    public function work() {
        $baseWork = parent::work();
        return $baseWork . " and managing a team of {$this->teamSize}";
    }
}

class Developer extends Employee {
    private $programmingLanguages;
    private $experience;
    
    public function __construct($name, $salary, $department, $experience, $languages = []) {
        parent::__construct($name, $salary, $department);
        $this->experience = $experience;
        $this->programmingLanguages = $languages;
    }
    
    public function getDetails() {
        $baseDetails = parent::getDetails();
        $languages = implode(", ", $this->programmingLanguages);
        return $baseDetails . ", Experience: {$this->experience} years, Languages: {$languages}";
    }
    
    public function calculateBonus() {
        $baseBonus = parent::calculateBonus();
        $experienceBonus = $this->experience * 200; // $200 per year of experience
        return $baseBonus + $experienceBonus;
    }
    
    public function writeCode($language) {
        if (in_array($language, $this->programmingLanguages)) {
            return "{$this->name} is writing code in {$language}";
        }
        return "{$this->name} needs to learn {$language} first";
    }
    
    public function work() {
        $baseWork = parent::work();
        return $baseWork . " and developing software";
    }
}

// Usage
$manager = new Manager("Sarah Johnson", 75000, "Engineering", 8);
echo $manager->getDetails();
// Output: Employee: Sarah Johnson, Salary: $75,000, Team Size: 8, Role: Manager

echo "Bonus: $" . number_format($manager->calculateBonus());
// Output: Bonus: $7,750 (base 5% + $500 per team member)

$developer = new Developer("John Smith", 65000, "Engineering", 5, ["PHP", "JavaScript", "Python"]);
echo $developer->getDetails();
// Output: Employee: John Smith, Salary: $65,000, Experience: 5 years, Languages: PHP, JavaScript, Python

echo $developer->writeCode("PHP");
// Output: John Smith is writing code in PHP
?>

Multilevel Inheritance

PHP supports inheritance chains where classes can inherit from other inherited classes:

<?php
class LivingBeing {
    protected $name;
    protected $lifespan;
    
    public function __construct($name, $lifespan) {
        $this->name = $name;
        $this->lifespan = $lifespan;
    }
    
    public function breathe() {
        return "{$this->name} is breathing";
    }
    
    public function age() {
        return "{$this->name} is aging";
    }
}

class Animal extends LivingBeing {
    protected $species;
    protected $habitat;
    
    public function __construct($name, $species, $habitat, $lifespan) {
        parent::__construct($name, $lifespan);
        $this->species = $species;
        $this->habitat = $habitat;
    }
    
    public function move() {
        return "{$this->name} is moving";
    }
    
    public function eat() {
        return "{$this->name} is eating";
    }
}

class Mammal extends Animal {
    protected $furColor;
    protected $warmBlooded = true;
    
    public function __construct($name, $species, $habitat, $lifespan, $furColor) {
        parent::__construct($name, $species, $habitat, $lifespan);
        $this->furColor = $furColor;
    }
    
    public function giveBirth() {
        return "{$this->name} gives birth to live offspring";
    }
    
    public function produceMilk() {
        return "{$this->name} produces milk for offspring";
    }
}

class Dog extends Mammal {
    private $breed;
    private $trainLevel;
    
    public function __construct($name, $breed, $furColor, $trainLevel = 1) {
        parent::__construct($name, "Canis lupus", "Domestic", 12, $furColor);
        $this->breed = $breed;
        $this->trainLevel = $trainLevel;
    }
    
    public function bark() {
        return "{$this->name} barks loudly";
    }
    
    public function fetch() {
        if ($this->trainLevel >= 2) {
            return "{$this->name} fetches the ball expertly";
        }
        return "{$this->name} is learning to fetch";
    }
    
    public function getCompleteInfo() {
        return "Name: {$this->name}, Breed: {$this->breed}, Color: {$this->furColor}, " .
               "Species: {$this->species}, Habitat: {$this->habitat}, Lifespan: {$this->lifespan} years";
    }
}

// Usage - Dog has access to methods from all parent classes
$dog = new Dog("Max", "Labrador", "Golden", 3);

// Methods from LivingBeing
echo $dog->breathe(); // Output: Max is breathing

// Methods from Animal  
echo $dog->move(); // Output: Max is moving
echo $dog->eat(); // Output: Max is eating

// Methods from Mammal
echo $dog->giveBirth(); // Output: Max gives birth to live offspring

// Methods from Dog
echo $dog->bark(); // Output: Max barks loudly
echo $dog->fetch(); // Output: Max fetches the ball expertly

echo $dog->getCompleteInfo();
// Output: Name: Max, Breed: Labrador, Color: Golden, Species: Canis lupus, Habitat: Domestic, Lifespan: 12 years
?>

Advanced Inheritance Patterns

Template Method Pattern

<?php
abstract class DataProcessor {
    // Template method defining the algorithm structure
    public final function processData($data) {
        $validatedData = $this->validateData($data);
        $transformedData = $this->transformData($validatedData);
        $result = $this->saveData($transformedData);
        $this->cleanup();
        
        return $result;
    }
    
    // Abstract methods to be implemented by subclasses
    abstract protected function validateData($data);
    abstract protected function transformData($data);
    abstract protected function saveData($data);
    
    // Hook method with default implementation
    protected function cleanup() {
        // Default cleanup - can be overridden
    }
}

class CSVProcessor extends DataProcessor {
    protected function validateData($data) {
        // CSV-specific validation
        if (!is_array($data)) {
            throw new InvalidArgumentException("CSV data must be an array");
        }
        return $data;
    }
    
    protected function transformData($data) {
        // Transform array to CSV format
        return array_map(function($row) {
            return implode(',', $row);
        }, $data);
    }
    
    protected function saveData($data) {
        $filename = 'data_' . date('Y-m-d_H-i-s') . '.csv';
        file_put_contents($filename, implode("\n", $data));
        return "Data saved to {$filename}";
    }
    
    protected function cleanup() {
        // CSV-specific cleanup
        echo "Temporary CSV files cleaned up\n";
    }
}

class JSONProcessor extends DataProcessor {
    protected function validateData($data) {
        // JSON-specific validation
        if (!is_array($data) && !is_object($data)) {
            throw new InvalidArgumentException("JSON data must be array or object");
        }
        return $data;
    }
    
    protected function transformData($data) {
        // Transform to JSON format
        return json_encode($data, JSON_PRETTY_PRINT);
    }
    
    protected function saveData($data) {
        $filename = 'data_' . date('Y-m-d_H-i-s') . '.json';
        file_put_contents($filename, $data);
        return "Data saved to {$filename}";
    }
}

// Usage
$csvProcessor = new CSVProcessor();
$result = $csvProcessor->processData([
    ['name', 'age', 'city'],
    ['John', '30', 'New York'],
    ['Jane', '25', 'Los Angeles']
]);

$jsonProcessor = new JSONProcessor();
$result = $jsonProcessor->processData([
    ['name' => 'John', 'age' => 30, 'city' => 'New York'],
    ['name' => 'Jane', 'age' => 25, 'city' => 'Los Angeles']
]);
?>

Best Practices for Inheritance

1. Follow the Liskov Substitution Principle

<?php
// Good example - child can replace parent
class Rectangle {
    protected $width;
    protected $height;
    
    public function setWidth($width) {
        $this->width = $width;
    }
    
    public function setHeight($height) {
        $this->height = $height;
    }
    
    public function getArea() {
        return $this->width * $this->height;
    }
}

// This violates LSP - Square cannot properly substitute Rectangle
class BadSquare extends Rectangle {
    public function setWidth($width) {
        $this->width = $width;
        $this->height = $width; // Problem: changes both dimensions
    }
    
    public function setHeight($height) {
        $this->width = $height;
        $this->height = $height; // Problem: changes both dimensions
    }
}

// Better approach - use composition or different hierarchy
abstract class Shape {
    abstract public function getArea();
}

class GoodRectangle extends Shape {
    protected $width;
    protected $height;
    
    public function __construct($width, $height) {
        $this->width = $width;
        $this->height = $height;
    }
    
    public function getArea() {
        return $this->width * $this->height;
    }
}

class GoodSquare extends Shape {
    protected $side;
    
    public function __construct($side) {
        $this->side = $side;
    }
    
    public function getArea() {
        return $this->side * $this->side;
    }
}
?>

2. Use Abstract Classes for Common Behavior

<?php
abstract class PaymentProcessor {
    protected $amount;
    protected $currency;
    
    public function __construct($amount, $currency = 'USD') {
        $this->amount = $amount;
        $this->currency = $currency;
    }
    
    // Common method for all payment processors
    public function validateAmount() {
        if ($this->amount <= 0) {
            throw new InvalidArgumentException("Amount must be positive");
        }
        return true;
    }
    
    // Template method
    public final function processPayment() {
        $this->validateAmount();
        $this->preProcess();
        $result = $this->executePayment();
        $this->postProcess();
        return $result;
    }
    
    // Abstract methods to be implemented by concrete classes
    abstract protected function executePayment();
    
    // Hook methods with default implementations
    protected function preProcess() {
        // Default pre-processing
    }
    
    protected function postProcess() {
        // Default post-processing
    }
}

class CreditCardProcessor extends PaymentProcessor {
    private $cardNumber;
    private $expiryDate;
    
    public function __construct($amount, $cardNumber, $expiryDate, $currency = 'USD') {
        parent::__construct($amount, $currency);
        $this->cardNumber = $cardNumber;
        $this->expiryDate = $expiryDate;
    }
    
    protected function executePayment() {
        // Credit card specific processing
        return "Processed ${$this->amount} {$this->currency} via Credit Card ending in " . 
               substr($this->cardNumber, -4);
    }
    
    protected function preProcess() {
        // Credit card specific pre-processing
        echo "Validating credit card details...\n";
    }
}

class PayPalProcessor extends PaymentProcessor {
    private $email;
    
    public function __construct($amount, $email, $currency = 'USD') {
        parent::__construct($amount, $currency);
        $this->email = $email;
    }
    
    protected function executePayment() {
        // PayPal specific processing
        return "Processed ${$this->amount} {$this->currency} via PayPal account {$this->email}";
    }
    
    protected function preProcess() {
        // PayPal specific pre-processing
        echo "Connecting to PayPal API...\n";
    }
}
?>

Common Inheritance Pitfalls

1. Deep Inheritance Hierarchies

<?php
// Avoid deep inheritance chains - they become hard to maintain
class A {
    public function methodA() {}
}

class B extends A {
    public function methodB() {}
}

class C extends B {
    public function methodC() {}
}

class D extends C {
    public function methodD() {}
}

class E extends D {
    public function methodE() {}
} // This is getting too deep!

// Better: Use composition and interfaces
interface CanFly {
    public function fly();
}

interface CanSwim {
    public function swim();
}

class Bird implements CanFly {
    public function fly() {
        return "Flying through the air";
    }
}

class Duck extends Bird implements CanSwim {
    public function swim() {
        return "Swimming in water";
    }
}
?>

2. Inappropriate Method Overriding

<?php
class BankAccount {
    protected $balance;
    
    public function __construct($initialBalance) {
        $this->balance = $initialBalance;
    }
    
    public function withdraw($amount) {
        if ($amount > $this->balance) {
            throw new Exception("Insufficient funds");
        }
        $this->balance -= $amount;
        return $this->balance;
    }
}

// Bad: Changes expected behavior
class BadSavingsAccount extends BankAccount {
    public function withdraw($amount) {
        // This violates expected behavior - should still check balance
        $this->balance -= $amount; // Allows overdraft!
        return $this->balance;
    }
}

// Good: Extends behavior appropriately
class GoodSavingsAccount extends BankAccount {
    private $minimumBalance;
    
    public function __construct($initialBalance, $minimumBalance = 100) {
        parent::__construct($initialBalance);
        $this->minimumBalance = $minimumBalance;
    }
    
    public function withdraw($amount) {
        if (($this->balance - $amount) < $this->minimumBalance) {
            throw new Exception("Cannot withdraw: would go below minimum balance");
        }
        return parent::withdraw($amount);
    }
}
?>

For more object-oriented programming concepts in PHP:

Summary

PHP inheritance enables:

  • Code Reusability: Share common functionality across related classes
  • Hierarchical Organization: Create logical class relationships
  • Method Overriding: Customize behavior in child classes
  • Polymorphism: Use child objects through parent interfaces
  • Template Patterns: Define algorithm structure in base classes

Key principles:

  • Use inheritance for "is-a" relationships
  • Follow the Liskov Substitution Principle
  • Prefer composition over deep inheritance
  • Override methods appropriately without breaking contracts
  • Use abstract classes for shared behavior with required implementations

Inheritance is a powerful feature that, when used correctly, makes code more maintainable and promotes good object-oriented design principles.