Polymorphism
Polymorphism is the ability of different classes to be treated as instances of the same class through a common interface. It allows methods to do different things based on the object they’re acting upon, even though they share the same name.
Understanding Polymorphism
Section titled “Understanding Polymorphism”The word “polymorphism” comes from Greek meaning “many forms”. In programming, it means that objects of different types can be accessed through the same interface.
Types of Polymorphism
Section titled “Types of Polymorphism”- Duck Typing - “If it walks like a duck and quacks like a duck, it’s a duck”
- Method Overriding - Subclasses override parent methods
- Operator Overloading - Same operator works differently for different types
Duck Typing
Section titled “Duck Typing”class Dog: def speak(self): return "Woof!"
class Cat: def speak(self): return "Meow!"
class Robot: def speak(self): return "Beep boop!"
def make_sound(animal): """Function works with any object that has a speak() method""" print(animal.speak())
# All these work - they all have a speak() methoddog = Dog()cat = Cat()robot = Robot()
make_sound(dog) # "Woof!"make_sound(cat) # "Meow!"make_sound(robot) # "Beep boop!"// Java uses interfaces for polymorphismpublic interface Speakable { String speak();}
public class Dog implements Speakable { @Override public String speak() { return "Woof!"; }}
public class Cat implements Speakable { @Override public String speak() { return "Meow!"; }}
public class Robot implements Speakable { @Override public String speak() { return "Beep boop!"; }}
// Function works with any object that implements Speakablepublic class Main { public static void makeSound(Speakable speaker) { System.out.println(speaker.speak()); }
public static void main(String[] args) { Speakable dog = new Dog(); Speakable cat = new Cat(); Speakable robot = new Robot();
makeSound(dog); // "Woof!" makeSound(cat); // "Meow!" makeSound(robot); // "Beep boop!" }}class Dog { speak(): string { return "Woof!"; }}
class Cat { speak(): string { return "Meow!"; }}
class Robot { speak(): string { return "Beep boop!"; }}
// Function works with any object that has a speak() methodfunction makeSound(speaker: { speak(): string }): void { console.log(speaker.speak());}
// All these work - they all have a speak() methodconst dog = new Dog();const cat = new Cat();const robot = new Robot();
makeSound(dog); // "Woof!"makeSound(cat); // "Meow!"makeSound(robot); // "Beep boop!"#include <iostream>#include <string>
// Interface (abstract class in C++)class Speakable {public: virtual std::string speak() const = 0; virtual ~Speakable() = default;};
class Dog : public Speakable {public: std::string speak() const override { return "Woof!"; }};
class Cat : public Speakable {public: std::string speak() const override { return "Meow!"; }};
class Robot : public Speakable {public: std::string speak() const override { return "Beep boop!"; }};
// Function works with any object that implements Speakablevoid makeSound(const Speakable* speaker) { std::cout << speaker->speak() << std::endl;}
int main() { Dog dog; Cat cat; Robot robot;
makeSound(&dog); // "Woof!" makeSound(&cat); // "Meow!" makeSound(&robot); // "Beep boop!"
return 0;}using System;
// Interfacepublic interface ISpeakable{ string Speak();}
public class Dog : ISpeakable{ public string Speak() { return "Woof!"; }}
public class Cat : ISpeakable{ public string Speak() { return "Meow!"; }}
public class Robot : ISpeakable{ public string Speak() { return "Beep boop!"; }}
class Program{ // Function works with any object that implements ISpeakable static void MakeSound(ISpeakable speaker) { Console.WriteLine(speaker.Speak()); }
static void Main() { ISpeakable dog = new Dog(); ISpeakable cat = new Cat(); ISpeakable robot = new Robot();
MakeSound(dog); // "Woof!" MakeSound(cat); // "Meow!" MakeSound(robot); // "Beep boop!" }}package main
import "fmt"
type Speakable interface{ Speak() string }
type Dog struct{}func (*Dog) Speak() string { return "Woof!" }
type Cat struct{}func (*Cat) Speak() string { return "Meow!" }
type Robot struct{}func (*Robot) Speak() string { return "Beep boop!" }
func makeSound(s Speakable) { fmt.Println(s.Speak())}
func main() { var dog Speakable = &Dog{} var cat Speakable = &Cat{} var robot Speakable = &Robot{} makeSound(dog) makeSound(cat) makeSound(robot)}Woof!Meow!Beep boop!trait Speakable { fn speak(&self) -> &str;}
struct Dog;struct Cat;struct Robot;
impl Speakable for Dog { fn speak(&self) -> &str { "Woof!" }}
impl Speakable for Cat { fn speak(&self) -> &str { "Meow!" }}
impl Speakable for Robot { fn speak(&self) -> &str { "Beep boop!" }}
fn make_sound(s: &dyn Speakable) { println!("{}", s.speak());}
fn main() { let dog: &dyn Speakable = &Dog; let cat: &dyn Speakable = &Cat; let robot: &dyn Speakable = &Robot; make_sound(dog); make_sound(cat); make_sound(robot);}Woof!Meow!Beep boop!Polymorphism Through Inheritance
Section titled “Polymorphism Through Inheritance”When classes inherit from a common base class, they can be used interchangeably:
class Vehicle: def __init__(self, brand: str, model: str, year: int): self.brand = brand self.model = model self.year = year
def start(self): """Base implementation""" return f"{self.brand} {self.model} started."
def get_info(self): return f"{self.brand} {self.model}, Year: {self.year}"
class Car(Vehicle): def start(self): """Polymorphic behavior - Car's version""" return f"{self.brand} {self.model} car started with a roar!"
class Motorcycle(Vehicle): def start(self): """Polymorphic behavior - Motorcycle's version""" return f"{self.brand} {self.model} motorcycle started with a vroom!"
class ElectricVehicle(Vehicle): def start(self): """Polymorphic behavior - Electric's version""" return f"{self.brand} {self.model} silently started (electric motor)"
def start_vehicle(vehicle: Vehicle): """Function accepts any Vehicle - polymorphism in action""" print(vehicle.start()) print(vehicle.get_info())
# All vehicles can be used interchangeablycar = Car("Toyota", "Camry", 2020)motorcycle = Motorcycle("Yamaha", "YZF-R3", 2021)electric = ElectricVehicle("Tesla", "Model 3", 2023)
start_vehicle(car) # Works - Car is a Vehiclestart_vehicle(motorcycle) # Works - Motorcycle is a Vehiclestart_vehicle(electric) # Works - ElectricVehicle is a Vehiclepublic class Vehicle { protected String brand; protected String model; protected int year;
public Vehicle(String brand, String model, int year) { this.brand = brand; this.model = model; this.year = year; }
// Base implementation public String start() { return brand + " " + model + " started."; }
public String getInfo() { return brand + " " + model + ", Year: " + year; }}
public class Car extends Vehicle { public Car(String brand, String model, int year) { super(brand, model, year); }
@Override public String start() { // Polymorphic behavior - Car's version return brand + " " + model + " car started with a roar!"; }}
public class Motorcycle extends Vehicle { public Motorcycle(String brand, String model, int year) { super(brand, model, year); }
@Override public String start() { // Polymorphic behavior - Motorcycle's version return brand + " " + model + " motorcycle started with a vroom!"; }}
public class ElectricVehicle extends Vehicle { public ElectricVehicle(String brand, String model, int year) { super(brand, model, year); }
@Override public String start() { // Polymorphic behavior - Electric's version return brand + " " + model + " silently started (electric motor)"; }}
// Function accepts any Vehicle - polymorphism in actionpublic class Main { public static void startVehicle(Vehicle vehicle) { System.out.println(vehicle.start()); System.out.println(vehicle.getInfo()); }
public static void main(String[] args) { // All vehicles can be used interchangeably Car car = new Car("Toyota", "Camry", 2020); Motorcycle motorcycle = new Motorcycle("Yamaha", "YZF-R3", 2021); ElectricVehicle electric = new ElectricVehicle("Tesla", "Model 3", 2023);
startVehicle(car); // Works - Car is a Vehicle startVehicle(motorcycle); // Works - Motorcycle is a Vehicle startVehicle(electric); // Works - ElectricVehicle is a Vehicle }}class Vehicle { protected brand: string; protected model: string; protected year: number;
constructor(brand: string, model: string, year: number) { this.brand = brand; this.model = model; this.year = year; }
// Base implementation start(): string { return `${this.brand} ${this.model} started.`; }
getInfo(): string { return `${this.brand} ${this.model}, Year: ${this.year}`; }}
class Car extends Vehicle { start(): string { // Polymorphic behavior - Car's version return `${this.brand} ${this.model} car started with a roar!`; }}
class Motorcycle extends Vehicle { start(): string { // Polymorphic behavior - Motorcycle's version return `${this.brand} ${this.model} motorcycle started with a vroom!`; }}
class ElectricVehicle extends Vehicle { start(): string { // Polymorphic behavior - Electric's version return `${this.brand} ${this.model} silently started (electric motor)`; }}
function startVehicle(vehicle: Vehicle): void { console.log(vehicle.start()); console.log(vehicle.getInfo());}
// All vehicles can be used interchangeablyconst car = new Car("Toyota", "Camry", 2020);const motorcycle = new Motorcycle("Yamaha", "YZF-R3", 2021);const electric = new ElectricVehicle("Tesla", "Model 3", 2023);
startVehicle(car); // Works - Car is a VehiclestartVehicle(motorcycle); // Works - Motorcycle is a VehiclestartVehicle(electric); // Works - ElectricVehicle is a Vehicle#include <iostream>#include <string>
class Vehicle {protected: std::string brand; std::string model; int year;
public: Vehicle(const std::string& brand, const std::string& model, int year) : brand(brand), model(model), year(year) {}
// Base implementation - virtual for polymorphism virtual std::string start() const { return brand + " " + model + " started."; }
std::string getInfo() const { return brand + " " + model + ", Year: " + std::to_string(year); }
virtual ~Vehicle() = default;};
class Car : public Vehicle {public: Car(const std::string& brand, const std::string& model, int year) : Vehicle(brand, model, year) {}
std::string start() const override { // Polymorphic behavior - Car's version return brand + " " + model + " car started with a roar!"; }};
class Motorcycle : public Vehicle {public: Motorcycle(const std::string& brand, const std::string& model, int year) : Vehicle(brand, model, year) {}
std::string start() const override { // Polymorphic behavior - Motorcycle's version return brand + " " + model + " motorcycle started with a vroom!"; }};
class ElectricVehicle : public Vehicle {public: ElectricVehicle(const std::string& brand, const std::string& model, int year) : Vehicle(brand, model, year) {}
std::string start() const override { // Polymorphic behavior - Electric's version return brand + " " + model + " silently started (electric motor)"; }};
void startVehicle(const Vehicle& vehicle) { std::cout << vehicle.start() << std::endl; std::cout << vehicle.getInfo() << std::endl;}
int main() { Car car("Toyota", "Camry", 2020); Motorcycle motorcycle("Yamaha", "YZF-R3", 2021); ElectricVehicle electric("Tesla", "Model 3", 2023);
startVehicle(car); // Works - Car is a Vehicle startVehicle(motorcycle); // Works - Motorcycle is a Vehicle startVehicle(electric); // Works - ElectricVehicle is a Vehicle
return 0;}using System;
public class Vehicle{ protected string brand; protected string model; protected int year;
public Vehicle(string brand, string model, int year) { this.brand = brand; this.model = model; this.year = year; }
// Base implementation - virtual for polymorphism public virtual string Start() { return $"{brand} {model} started."; }
public string GetInfo() { return $"{brand} {model}, Year: {year}"; }}
public class Car : Vehicle{ public Car(string brand, string model, int year) : base(brand, model, year) {}
public override string Start() { // Polymorphic behavior - Car's version return $"{brand} {model} car started with a roar!"; }}
public class Motorcycle : Vehicle{ public Motorcycle(string brand, string model, int year) : base(brand, model, year) {}
public override string Start() { // Polymorphic behavior - Motorcycle's version return $"{brand} {model} motorcycle started with a vroom!"; }}
public class ElectricVehicle : Vehicle{ public ElectricVehicle(string brand, string model, int year) : base(brand, model, year) {}
public override string Start() { // Polymorphic behavior - Electric's version return $"{brand} {model} silently started (electric motor)"; }}
class Program{ static void StartVehicle(Vehicle vehicle) { Console.WriteLine(vehicle.Start()); Console.WriteLine(vehicle.GetInfo()); }
static void Main() { Car car = new Car("Toyota", "Camry", 2020); Motorcycle motorcycle = new Motorcycle("Yamaha", "YZF-R3", 2021); ElectricVehicle electric = new ElectricVehicle("Tesla", "Model 3", 2023);
StartVehicle(car); // Works - Car is a Vehicle StartVehicle(motorcycle); // Works - Motorcycle is a Vehicle StartVehicle(electric); // Works - ElectricVehicle is a Vehicle }}package main
import "fmt"
type Vehicle struct { Brand, Model string Year int}
func (v *Vehicle) Start() string { return fmt.Sprintf("%s %s started.", v.Brand, v.Model)}
func (v *Vehicle) GetInfo() string { return fmt.Sprintf("%s %s, Year: %d", v.Brand, v.Model, v.Year)}
type Car struct{ Vehicle }
func (c *Car) Start() string { return fmt.Sprintf("%s %s car started with a roar!", c.Brand, c.Model)}
type Motorcycle struct{ Vehicle }
func (m *Motorcycle) Start() string { return fmt.Sprintf("%s %s motorcycle started with a vroom!", m.Brand, m.Model)}
type ElectricVehicle struct{ Vehicle }
func (e *ElectricVehicle) Start() string { return fmt.Sprintf("%s %s silently started (electric motor)", e.Brand, e.Model)}
func startVehicle(v VehicleLike) { fmt.Println(v.Start()) fmt.Println(v.GetInfo())}
type VehicleLike interface { Start() string GetInfo() string}
func main() { startVehicle(&Car{Vehicle: Vehicle{"Toyota", "Camry", 2020}}) startVehicle(&Motorcycle{Vehicle: Vehicle{"Yamaha", "YZF-R3", 2021}}) startVehicle(&ElectricVehicle{Vehicle: Vehicle{"Tesla", "Model 3", 2023}})}struct Vehicle { brand: String, model: String, year: u32,}
impl Vehicle { fn start(&self) -> String { format!("{} {} started.", self.brand, self.model) }
fn get_info(&self) -> String { format!("{} {}, Year: {}", self.brand, self.model, self.year) }}
struct Car { vehicle: Vehicle,}
impl Car { fn start(&self) -> String { format!("{} {} car started with a roar!", self.vehicle.brand, self.vehicle.model) }}
struct Motorcycle { vehicle: Vehicle,}
impl Motorcycle { fn start(&self) -> String { format!( "{} {} motorcycle started with a vroom!", self.vehicle.brand, self.vehicle.model ) }}
struct ElectricVehicle { vehicle: Vehicle,}
impl ElectricVehicle { fn start(&self) -> String { format!( "{} {} silently started (electric motor)", self.vehicle.brand, self.vehicle.model ) }}
trait VehicleLike { fn start(&self) -> String; fn get_info(&self) -> String;}
impl VehicleLike for Car { fn start(&self) -> String { Car::start(self) }
fn get_info(&self) -> String { self.vehicle.get_info() }}
impl VehicleLike for Motorcycle { fn start(&self) -> String { Motorcycle::start(self) }
fn get_info(&self) -> String { self.vehicle.get_info() }}
impl VehicleLike for ElectricVehicle { fn start(&self) -> String { ElectricVehicle::start(self) }
fn get_info(&self) -> String { self.vehicle.get_info() }}
fn start_vehicle(v: &dyn VehicleLike) { println!("{}", v.start()); println!("{}", v.get_info());}
fn main() { start_vehicle(&Car { vehicle: Vehicle { brand: "Toyota".into(), model: "Camry".into(), year: 2020, }, }); start_vehicle(&Motorcycle { vehicle: Vehicle { brand: "Yamaha".into(), model: "YZF-R3".into(), year: 2021, }, }); start_vehicle(&ElectricVehicle { vehicle: Vehicle { brand: "Tesla".into(), model: "Model 3".into(), year: 2023, }, });}Real-World Example: Payment Processing
Section titled “Real-World Example: Payment Processing”class PaymentMethod: """Base class for payment methods""" def process_payment(self, amount: float) -> bool: raise NotImplementedError("Subclass must implement process_payment")
class CreditCard(PaymentMethod): def __init__(self, card_number: str, cvv: str): self.card_number = card_number self.cvv = cvv
def process_payment(self, amount: float) -> bool: """Process credit card payment""" print(f"Processing ${amount:.2f} via credit card ending in {self.card_number[-4:]}") # Credit card processing logic return True
class PayPal(PaymentMethod): def __init__(self, email: str): self.email = email
def process_payment(self, amount: float) -> bool: """Process PayPal payment""" print(f"Processing ${amount:.2f} via PayPal ({self.email})") # PayPal processing logic return True
class BankTransfer(PaymentMethod): def __init__(self, account_number: str): self.account_number = account_number
def process_payment(self, amount: float) -> bool: """Process bank transfer""" print(f"Processing ${amount:.2f} via bank transfer (Account: {self.account_number})") # Bank transfer logic return True
class ShoppingCart: """Shopping cart that accepts any payment method""" def __init__(self): self.items = [] self.total = 0.0
def add_item(self, item: str, price: float): self.items.append((item, price)) self.total += price
def checkout(self, payment_method: PaymentMethod) -> bool: """Polymorphic method - works with any PaymentMethod""" print(f"Checking out {len(self.items)} items, Total: ${self.total:.2f}") return payment_method.process_payment(self.total)
# Usage - polymorphism allows using different payment methods interchangeablycart = ShoppingCart()cart.add_item("Laptop", 999.99)cart.add_item("Mouse", 29.99)
# All payment methods work the same waycredit_card = CreditCard("1234567890123456", "123")bank_transfer = BankTransfer("ACC-12345")
cart.checkout(credit_card) # Workscart.checkout(paypal) # Workscart.checkout(bank_transfer) # Works// Base class for payment methodspublic abstract class PaymentMethod { public abstract boolean processPayment(double amount);}
public class CreditCard extends PaymentMethod { private String cardNumber; private String cvv;
public CreditCard(String cardNumber, String cvv) { this.cardNumber = cardNumber; this.cvv = cvv; }
@Override public boolean processPayment(double amount) { // Process credit card payment String lastFour = cardNumber.substring(cardNumber.length() - 4); System.out.printf("Processing $%.2f via credit card ending in %s%n", amount, lastFour); // Credit card processing logic return true; }}
public class PayPal extends PaymentMethod { private String email;
public PayPal(String email) { this.email = email; }
@Override public boolean processPayment(double amount) { // Process PayPal payment System.out.printf("Processing $%.2f via PayPal (%s)%n", amount, email); // PayPal processing logic return true; }}
public class BankTransfer extends PaymentMethod { private String accountNumber;
public BankTransfer(String accountNumber) { this.accountNumber = accountNumber; }
@Override public boolean processPayment(double amount) { // Process bank transfer System.out.printf("Processing $%.2f via bank transfer (Account: %s)%n", amount, accountNumber); // Bank transfer logic return true; }}
// Shopping cart that accepts any payment methodpublic class ShoppingCart { private java.util.List<String> items; private double total;
public ShoppingCart() { this.items = new java.util.ArrayList<>(); this.total = 0.0; }
public void addItem(String item, double price) { items.add(item); total += price; }
// Polymorphic method - works with any PaymentMethod public boolean checkout(PaymentMethod paymentMethod) { System.out.printf("Checking out %d items, Total: $%.2f%n", items.size(), total); return paymentMethod.processPayment(total); }}
// Usage - polymorphism allows using different payment methods interchangeablypublic class Main { public static void main(String[] args) { ShoppingCart cart = new ShoppingCart(); cart.addItem("Laptop", 999.99); cart.addItem("Mouse", 29.99);
// All payment methods work the same way PaymentMethod creditCard = new CreditCard("1234567890123456", "123"); PaymentMethod bankTransfer = new BankTransfer("ACC-12345");
cart.checkout(creditCard); // Works cart.checkout(paypal); // Works cart.checkout(bankTransfer); // Works }}// Base class for payment methodsabstract class PaymentMethod { abstract processPayment(amount: number): boolean;}
class CreditCard extends PaymentMethod { private cardNumber: string; private cvv: string;
constructor(cardNumber: string, cvv: string) { super(); this.cardNumber = cardNumber; this.cvv = cvv; }
processPayment(amount: number): boolean { const lastFour = this.cardNumber.slice(-4); console.log(`Processing $${amount.toFixed(2)} via credit card ending in ${lastFour}`); return true; }}
class PayPal extends PaymentMethod { private email: string;
constructor(email: string) { super(); this.email = email; }
processPayment(amount: number): boolean { console.log(`Processing $${amount.toFixed(2)} via PayPal (${this.email})`); return true; }}
class BankTransfer extends PaymentMethod { private accountNumber: string;
constructor(accountNumber: string) { super(); this.accountNumber = accountNumber; }
processPayment(amount: number): boolean { console.log(`Processing $${amount.toFixed(2)} via bank transfer (Account: ${this.accountNumber})`); return true; }}
class ShoppingCart { private items: Array<[string, number]> = []; private total: number = 0;
addItem(item: string, price: number): void { this.items.push([item, price]); this.total += price; }
checkout(paymentMethod: PaymentMethod): boolean { console.log(`Checking out ${this.items.length} items, Total: $${this.total.toFixed(2)}`); return paymentMethod.processPayment(this.total); }}
// Usageconst cart = new ShoppingCart();cart.addItem("Laptop", 999.99);cart.addItem("Mouse", 29.99);
const creditCard = new CreditCard("1234567890123456", "123");const bankTransfer = new BankTransfer("ACC-12345");
cart.checkout(creditCard); // Workscart.checkout(paypal); // Workscart.checkout(bankTransfer); // Works#include <iostream>#include <string>#include <vector>#include <iomanip>
// Base class for payment methodsclass PaymentMethod {public: virtual bool processPayment(double amount) = 0; virtual ~PaymentMethod() = default;};
class CreditCard : public PaymentMethod {private: std::string cardNumber; std::string cvv;
public: CreditCard(const std::string& cardNumber, const std::string& cvv) : cardNumber(cardNumber), cvv(cvv) {}
bool processPayment(double amount) override { std::string lastFour = cardNumber.substr(cardNumber.length() - 4); std::cout << std::fixed << std::setprecision(2); std::cout << "Processing $" << amount << " via credit card ending in " << lastFour << std::endl; return true; }};
class PayPal : public PaymentMethod {private: std::string email;
public: PayPal(const std::string& email) : email(email) {}
bool processPayment(double amount) override { std::cout << std::fixed << std::setprecision(2); std::cout << "Processing $" << amount << " via PayPal (" << email << ")" << std::endl; return true; }};
class BankTransfer : public PaymentMethod {private: std::string accountNumber;
public: BankTransfer(const std::string& accountNumber) : accountNumber(accountNumber) {}
bool processPayment(double amount) override { std::cout << std::fixed << std::setprecision(2); std::cout << "Processing $" << amount << " via bank transfer (Account: " << accountNumber << ")" << std::endl; return true; }};
class ShoppingCart {private: std::vector<std::pair<std::string, double>> items; double total;
public: ShoppingCart() : total(0.0) {}
void addItem(const std::string& item, double price) { items.push_back({item, price}); total += price; }
bool checkout(PaymentMethod* paymentMethod) { std::cout << "Checking out " << items.size() << " items, Total: $" << std::fixed << std::setprecision(2) << total << std::endl; return paymentMethod->processPayment(total); }};
int main() { ShoppingCart cart; cart.addItem("Laptop", 999.99); cart.addItem("Mouse", 29.99);
CreditCard creditCard("1234567890123456", "123"); BankTransfer bankTransfer("ACC-12345");
cart.checkout(&creditCard); // Works cart.checkout(&paypal); // Works cart.checkout(&bankTransfer); // Works
return 0;}using System;using System.Collections.Generic;
// Base class for payment methodspublic abstract class PaymentMethod{ public abstract bool ProcessPayment(double amount);}
public class CreditCard : PaymentMethod{ private string cardNumber; private string cvv;
public CreditCard(string cardNumber, string cvv) { this.cardNumber = cardNumber; this.cvv = cvv; }
public override bool ProcessPayment(double amount) { string lastFour = cardNumber.Substring(cardNumber.Length - 4); Console.WriteLine($"Processing ${amount:F2} via credit card ending in {lastFour}"); return true; }}
public class PayPal : PaymentMethod{ private string email;
public PayPal(string email) { this.email = email; }
public override bool ProcessPayment(double amount) { Console.WriteLine($"Processing ${amount:F2} via PayPal ({email})"); return true; }}
public class BankTransfer : PaymentMethod{ private string accountNumber;
public BankTransfer(string accountNumber) { this.accountNumber = accountNumber; }
public override bool ProcessPayment(double amount) { Console.WriteLine($"Processing ${amount:F2} via bank transfer (Account: {accountNumber})"); return true; }}
public class ShoppingCart{ private List<Tuple<string, double>> items = new List<Tuple<string, double>>(); private double total = 0.0;
public void AddItem(string item, double price) { items.Add(new Tuple<string, double>(item, price)); total += price; }
public bool Checkout(PaymentMethod paymentMethod) { Console.WriteLine($"Checking out {items.Count} items, Total: ${total:F2}"); return paymentMethod.ProcessPayment(total); }}
class Program{ static void Main() { ShoppingCart cart = new ShoppingCart(); cart.AddItem("Laptop", 999.99); cart.AddItem("Mouse", 29.99);
PaymentMethod creditCard = new CreditCard("1234567890123456", "123"); PaymentMethod bankTransfer = new BankTransfer("ACC-12345");
cart.Checkout(creditCard); // Works cart.Checkout(paypal); // Works cart.Checkout(bankTransfer); // Works }}package main
import "fmt"
type PaymentMethod interface { ProcessPayment(amount float64) bool}
type CreditCard struct { CardNumber, CVV string}
func (c *CreditCard) ProcessPayment(amount float64) bool { last4 := c.CardNumber[max(0, len(c.CardNumber)-4):] fmt.Printf("Processing $%.2f via credit card ending in %s\n", amount, last4) return true}
type PayPal struct{ Email string }
func (p *PayPal) ProcessPayment(amount float64) bool { fmt.Printf("Processing $%.2f via PayPal (%s)\n", amount, p.Email) return true}
type BankTransfer struct{ Account string }
func (b *BankTransfer) ProcessPayment(amount float64) bool { fmt.Printf("Processing $%.2f via bank transfer (Account: %s)\n", amount, b.Account) return true}
type ShoppingCart struct { Items []string Total float64}
func (sc *ShoppingCart) AddItem(item string, price float64) { sc.Items = append(sc.Items, item) sc.Total += price}
func (sc *ShoppingCart) Checkout(pm PaymentMethod) bool { fmt.Printf("Checking out %d items, Total: $%.2f\n", len(sc.Items), sc.Total) return pm.ProcessPayment(sc.Total)}
func max(a, b int) int { if a > b { return a } return b}
func main() { cart := &ShoppingCart{} cart.AddItem("Laptop", 999.99) cart.AddItem("Mouse", 29.99)
cc := &CreditCard{CardNumber: "1234567890123456", CVV: "123"} bt := &BankTransfer{Account: "ACC-12345"}
cart.Checkout(cc) cart.Checkout(pp) cart.Checkout(bt)}trait PaymentMethod { fn process_payment(&self, amount: f64) -> bool;}
struct CreditCard { card_number: String, cvv: String,}
impl PaymentMethod for CreditCard { fn process_payment(&self, amount: f64) -> bool { let last4 = self .card_number .chars() .rev() .take(4) .collect::<String>() .chars() .rev() .collect::<String>(); println!( "Processing ${:.2} via credit card ending in {}", amount, last4 ); true }}
struct PayPal { email: String,}
impl PaymentMethod for PayPal { fn process_payment(&self, amount: f64) -> bool { println!("Processing ${:.2} via PayPal ({})", amount, self.email); true }}
struct BankTransfer { account: String,}
impl PaymentMethod for BankTransfer { fn process_payment(&self, amount: f64) -> bool { println!( "Processing ${:.2} via bank transfer (Account: {})", amount, self.account ); true }}
struct ShoppingCart { items: Vec<String>, total: f64,}
impl ShoppingCart { fn add_item(&mut self, item: impl Into<String>, price: f64) { self.items.push(item.into()); self.total += price; }
fn checkout(&self, pm: &dyn PaymentMethod) -> bool { println!( "Checking out {} items, Total: ${:.2}", self.items.len(), self.total ); pm.process_payment(self.total) }}
fn main() { let mut cart = ShoppingCart { items: vec![], total: 0.0, }; cart.add_item("Laptop", 999.99); cart.add_item("Mouse", 29.99);
let cc = CreditCard { card_number: "1234567890123456".into(), cvv: "123".into(), }; let pp = PayPal { }; let bt = BankTransfer { account: "ACC-12345".into(), };
cart.checkout(&cc); cart.checkout(&pp); cart.checkout(&bt);}Polymorphism with Abstract Classes
Section titled “Polymorphism with Abstract Classes”Using abstract classes ensures all implementations provide required methods:
from abc import ABC, abstractmethod
class Shape(ABC): """Abstract base class""" @abstractmethod def area(self) -> float: pass
@abstractmethod def perimeter(self) -> float: pass
class Rectangle(Shape): def __init__(self, width: float, height: float): self.width = width self.height = height
def area(self) -> float: return self.width * self.height
def perimeter(self) -> float: return 2 * (self.width + self.height)
class Circle(Shape): def __init__(self, radius: float): self.radius = radius
def area(self) -> float: import math return math.pi * self.radius ** 2
def perimeter(self) -> float: import math return 2 * math.pi * self.radius
class Triangle(Shape): def __init__(self, a: float, b: float, c: float): self.a = a self.b = b self.c = c
def area(self) -> float: # Heron's formula s = self.perimeter() / 2 return (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5
def perimeter(self) -> float: return self.a + self.b + self.c
def print_shape_info(shape: Shape): """Polymorphic function - works with any Shape""" print(f"Area: {shape.area():.2f}") print(f"Perimeter: {shape.perimeter():.2f}")
# All shapes can be used interchangeablyrectangle = Rectangle(5, 3)circle = Circle(4)triangle = Triangle(3, 4, 5)
print_shape_info(rectangle) # Worksprint_shape_info(circle) # Worksprint_shape_info(triangle) # Works// Abstract base classpublic abstract class Shape { public abstract double area(); public abstract double perimeter();}
public class Rectangle extends Shape { private double width; private double height;
public Rectangle(double width, double height) { this.width = width; this.height = height; }
@Override public double area() { return width * height; }
@Override public double perimeter() { return 2 * (width + height); }}
public class Circle extends Shape { private double radius;
public Circle(double radius) { this.radius = radius; }
@Override public double area() { return Math.PI * radius * radius; }
@Override public double perimeter() { return 2 * Math.PI * radius; }}
public class Triangle extends Shape { private double a; private double b; private double c;
public Triangle(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
@Override public double area() { // Heron's formula double s = perimeter() / 2; return Math.sqrt(s * (s - a) * (s - b) * (s - c)); }
@Override public double perimeter() { return a + b + c; }}
// Polymorphic function - works with any Shapepublic class Main { public static void printShapeInfo(Shape shape) { System.out.printf("Area: %.2f%n", shape.area()); System.out.printf("Perimeter: %.2f%n", shape.perimeter()); }
public static void main(String[] args) { // All shapes can be used interchangeably Rectangle rectangle = new Rectangle(5, 3); Circle circle = new Circle(4); Triangle triangle = new Triangle(3, 4, 5);
printShapeInfo(rectangle); // Works printShapeInfo(circle); // Works printShapeInfo(triangle); // Works }}// Abstract base classabstract class Shape { abstract area(): number; abstract perimeter(): number;}
class Rectangle extends Shape { constructor(private width: number, private height: number) { super(); }
area(): number { return this.width * this.height; }
perimeter(): number { return 2 * (this.width + this.height); }}
class Circle extends Shape { constructor(private radius: number) { super(); }
area(): number { return Math.PI * this.radius ** 2; }
perimeter(): number { return 2 * Math.PI * this.radius; }}
class Triangle extends Shape { constructor(private a: number, private b: number, private c: number) { super(); }
area(): number { // Heron's formula const s = this.perimeter() / 2; return Math.sqrt(s * (s - this.a) * (s - this.b) * (s - this.c)); }
perimeter(): number { return this.a + this.b + this.c; }}
function printShapeInfo(shape: Shape): void { console.log(`Area: ${shape.area().toFixed(2)}`); console.log(`Perimeter: ${shape.perimeter().toFixed(2)}`);}
// All shapes can be used interchangeablyconst rectangle = new Rectangle(5, 3);const circle = new Circle(4);const triangle = new Triangle(3, 4, 5);
printShapeInfo(rectangle); // WorksprintShapeInfo(circle); // WorksprintShapeInfo(triangle); // Works#include <iostream>#include <cmath>#include <iomanip>
// Abstract base classclass Shape {public: virtual double area() const = 0; virtual double perimeter() const = 0; virtual ~Shape() = default;};
class Rectangle : public Shape {private: double width; double height;
public: Rectangle(double width, double height) : width(width), height(height) {}
double area() const override { return width * height; }
double perimeter() const override { return 2 * (width + height); }};
class Circle : public Shape {private: double radius;
public: Circle(double radius) : radius(radius) {}
double area() const override { return M_PI * radius * radius; }
double perimeter() const override { return 2 * M_PI * radius; }};
class Triangle : public Shape {private: double a, b, c;
public: Triangle(double a, double b, double c) : a(a), b(b), c(c) {}
double area() const override { // Heron's formula double s = perimeter() / 2; return sqrt(s * (s - a) * (s - b) * (s - c)); }
double perimeter() const override { return a + b + c; }};
void printShapeInfo(const Shape& shape) { std::cout << std::fixed << std::setprecision(2); std::cout << "Area: " << shape.area() << std::endl; std::cout << "Perimeter: " << shape.perimeter() << std::endl;}
int main() { Rectangle rectangle(5, 3); Circle circle(4); Triangle triangle(3, 4, 5);
printShapeInfo(rectangle); // Works printShapeInfo(circle); // Works printShapeInfo(triangle); // Works
return 0;}using System;
// Abstract base classpublic abstract class Shape{ public abstract double Area(); public abstract double Perimeter();}
public class Rectangle : Shape{ private double width; private double height;
public Rectangle(double width, double height) { this.width = width; this.height = height; }
public override double Area() { return width * height; }
public override double Perimeter() { return 2 * (width + height); }}
public class Circle : Shape{ private double radius;
public Circle(double radius) { this.radius = radius; }
public override double Area() { return Math.PI * radius * radius; }
public override double Perimeter() { return 2 * Math.PI * radius; }}
public class Triangle : Shape{ private double a, b, c;
public Triangle(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
public override double Area() { // Heron's formula double s = Perimeter() / 2; return Math.Sqrt(s * (s - a) * (s - b) * (s - c)); }
public override double Perimeter() { return a + b + c; }}
class Program{ static void PrintShapeInfo(Shape shape) { Console.WriteLine($"Area: {shape.Area():F2}"); Console.WriteLine($"Perimeter: {shape.Perimeter():F2}"); }
static void Main() { Rectangle rectangle = new Rectangle(5, 3); Circle circle = new Circle(4); Triangle triangle = new Triangle(3, 4, 5);
PrintShapeInfo(rectangle); // Works PrintShapeInfo(circle); // Works PrintShapeInfo(triangle); // Works }}package main
import ( "fmt" "math")
type Shape interface { Area() float64 Perimeter() float64}
type Rectangle struct{ Width, Height float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) }
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius }func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius }
type Triangle struct{ A, B, C float64 }
func (t Triangle) Perimeter() float64 { return t.A + t.B + t.C }
func (t Triangle) Area() float64 { s := t.Perimeter() / 2 return math.Sqrt(s * (s - t.A) * (s - t.B) * (s - t.C))}
func printShapeInfo(s Shape) { fmt.Printf("Area: %.2f\n", s.Area()) fmt.Printf("Perimeter: %.2f\n", s.Perimeter())}
func main() { printShapeInfo(Rectangle{5, 3}) printShapeInfo(Circle{4}) printShapeInfo(Triangle{3, 4, 5})}trait Shape { fn area(&self) -> f64; fn perimeter(&self) -> f64;}
struct Rectangle { width: f64, height: f64,}
impl Shape for Rectangle { fn area(&self) -> f64 { self.width * self.height }
fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) }}
struct Circle { radius: f64,}
impl Shape for Circle { fn area(&self) -> f64 { std::f64::consts::PI * self.radius * self.radius }
fn perimeter(&self) -> f64 { 2.0 * std::f64::consts::PI * self.radius }}
struct Triangle { a: f64, b: f64, c: f64,}
impl Shape for Triangle { fn perimeter(&self) -> f64 { self.a + self.b + self.c }
fn area(&self) -> f64 { let s = self.perimeter() / 2.0; (s * (s - self.a) * (s - self.b) * (s - self.c)).sqrt() }}
fn print_shape_info(s: &dyn Shape) { println!("Area: {:.2}", s.area()); println!("Perimeter: {:.2}", s.perimeter());}
fn main() { print_shape_info(&Rectangle { width: 5.0, height: 3.0 }); print_shape_info(&Circle { radius: 4.0 }); print_shape_info(&Triangle { a: 3.0, b: 4.0, c: 5.0 });}Operator Overloading (Polymorphism)
Section titled “Operator Overloading (Polymorphism)”The same operator can work differently for different types:
class Vector: def __init__(self, x: float, y: float): self.x = x self.y = y
def __add__(self, other): """+ operator - polymorphic behavior""" if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) elif isinstance(other, (int, float)): return Vector(self.x + other, self.y + other) return NotImplemented
def __mul__(self, scalar): """* operator - polymorphic behavior""" return Vector(self.x * scalar, self.y * scalar)
def __str__(self): return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)v2 = Vector(3, 4)
# Same + operator, different behaviorresult1 = v1 + v2 # Vector additionresult2 = v1 + 5 # Scalar additionresult3 = v1 * 3 # Scalar multiplication
print(result1) # Vector(4, 6)print(result2) # Vector(6, 7)print(result3) # Vector(3, 6)public class Vector { private double x; private double y;
public Vector(double x, double y) { this.x = x; this.y = y; }
// Add another vector public Vector add(Vector other) { return new Vector(this.x + other.x, this.y + other.y); }
// Add scalar to vector public Vector add(double scalar) { return new Vector(this.x + scalar, this.y + scalar); }
// Multiply vector by scalar public Vector multiply(double scalar) { return new Vector(this.x * scalar, this.y * scalar); }
@Override public String toString() { return String.format("Vector(%.1f, %.1f)", x, y); }}
// Usagepublic class Main { public static void main(String[] args) { Vector v1 = new Vector(1, 2); Vector v2 = new Vector(3, 4);
// Use methods instead of operators Vector result1 = v1.add(v2); // Vector addition Vector result2 = v1.add(5); // Scalar addition Vector result3 = v1.multiply(3); // Scalar multiplication
System.out.println(result1); // Vector(4.0, 6.0) System.out.println(result2); // Vector(6.0, 7.0) System.out.println(result3); // Vector(3.0, 6.0) }}Note: Java doesn’t support operator overloading for user-defined classes (except for + with strings). Use methods like add(), multiply(), etc. instead.
class Vector { constructor(public x: number, public y: number) {}
// Add another vector add(other: Vector): Vector { return new Vector(this.x + other.x, this.y + other.y); }
// Add scalar to vector addScalar(scalar: number): Vector { return new Vector(this.x + scalar, this.y + scalar); }
// Multiply vector by scalar multiply(scalar: number): Vector { return new Vector(this.x * scalar, this.y * scalar); }
toString(): string { return `Vector(${this.x}, ${this.y})`; }}
const v1 = new Vector(1, 2);const v2 = new Vector(3, 4);
// Use methods instead of operatorsconst result1 = v1.add(v2); // Vector additionconst result2 = v1.addScalar(5); // Scalar additionconst result3 = v1.multiply(3); // Scalar multiplication
console.log(result1.toString()); // Vector(4, 6)console.log(result2.toString()); // Vector(6, 7)console.log(result3.toString()); // Vector(3, 6)#include <iostream>
class Vector {private: double x, y;
public: Vector(double x, double y) : x(x), y(y) {}
// + operator - polymorphic behavior for Vector Vector operator+(const Vector& other) const { return Vector(x + other.x, y + other.y); }
// + operator - polymorphic behavior for scalar Vector operator+(double scalar) const { return Vector(x + scalar, y + scalar); }
// * operator - scalar multiplication Vector operator*(double scalar) const { return Vector(x * scalar, y * scalar); }
friend std::ostream& operator<<(std::ostream& os, const Vector& v) { os << "Vector(" << v.x << ", " << v.y << ")"; return os; }};
int main() { Vector v1(1, 2); Vector v2(3, 4);
// Same + operator, different behavior Vector result1 = v1 + v2; // Vector addition Vector result2 = v1 + 5; // Scalar addition Vector result3 = v1 * 3; // Scalar multiplication
std::cout << result1 << std::endl; // Vector(4, 6) std::cout << result2 << std::endl; // Vector(6, 7) std::cout << result3 << std::endl; // Vector(3, 6)
return 0;}using System;
public class Vector{ public double X { get; set; } public double Y { get; set; }
public Vector(double x, double y) { X = x; Y = y; }
// + operator - polymorphic behavior for Vector public static Vector operator +(Vector v1, Vector v2) { return new Vector(v1.X + v2.X, v1.Y + v2.Y); }
// + operator - polymorphic behavior for scalar public static Vector operator +(Vector v, double scalar) { return new Vector(v.X + scalar, v.Y + scalar); }
// * operator - scalar multiplication public static Vector operator *(Vector v, double scalar) { return new Vector(v.X * scalar, v.Y * scalar); }
public override string ToString() { return $"Vector({X}, {Y})"; }}
class Program{ static void Main() { Vector v1 = new Vector(1, 2); Vector v2 = new Vector(3, 4);
// Same + operator, different behavior Vector result1 = v1 + v2; // Vector addition Vector result2 = v1 + 5; // Scalar addition Vector result3 = v1 * 3; // Scalar multiplication
Console.WriteLine(result1); // Vector(4, 6) Console.WriteLine(result2); // Vector(6, 7) Console.WriteLine(result3); // Vector(3, 6) }}package main
import "fmt"
type Vector struct{ X, Y float64 }
func (v Vector) Add(other Vector) Vector { return Vector{v.X + other.X, v.Y + other.Y}}
func (v Vector) AddScalar(scalar float64) Vector { return Vector{v.X + scalar, v.Y + scalar}}
func (v Vector) Mul(scalar float64) Vector { return Vector{v.X * scalar, v.Y * scalar}}
func (v Vector) String() string { return fmt.Sprintf("Vector(%g, %g)", v.X, v.Y)}
func main() { v1 := Vector{1, 2} v2 := Vector{3, 4} r1 := v1.Add(v2) r2 := v1.AddScalar(5) r3 := v1.Mul(3) fmt.Println(r1) fmt.Println(r2) fmt.Println(r3)}#[derive(Debug, Clone, Copy)]struct Vector { x: f64, y: f64,}
impl Vector { fn add(self, other: Vector) -> Vector { Vector { x: self.x + other.x, y: self.y + other.y, } }
fn add_scalar(self, scalar: f64) -> Vector { Vector { x: self.x + scalar, y: self.y + scalar, } }
fn mul(self, scalar: f64) -> Vector { Vector { x: self.x * scalar, y: self.y * scalar, } }}
fn main() { let v1 = Vector { x: 1.0, y: 2.0 }; let v2 = Vector { x: 3.0, y: 4.0 }; let r1 = v1.add(v2); let r2 = v1.add_scalar(5.0); let r3 = v1.mul(3.0); println!("{:?}", r1); println!("{:?}", r2); println!("{:?}", r3);}Real-World Example: Notification System
Section titled “Real-World Example: Notification System”class Notification: """Base notification class""" def send(self, message: str) -> bool: raise NotImplementedError("Subclass must implement send()")
class EmailNotification(Notification): def __init__(self, recipient: str): self.recipient = recipient
def send(self, message: str) -> bool: """Email-specific implementation""" print(f"Sending email to {self.recipient}: {message}") return True
class SMSNotification(Notification): def __init__(self, phone_number: str): self.phone_number = phone_number
def send(self, message: str) -> bool: """SMS-specific implementation""" print(f"Sending SMS to {self.phone_number}: {message[:50]}...") return True
class PushNotification(Notification): def __init__(self, device_id: str): self.device_id = device_id
def send(self, message: str) -> bool: """Push notification-specific implementation""" print(f"Sending push to device {self.device_id}: {message}") return True
class NotificationService: """Service that can use any notification type""" def __init__(self): self.notifications = []
def add_notification(self, notification: Notification): """Add any notification type""" self.notifications.append(notification)
def broadcast(self, message: str): """Send message through all notification channels""" for notification in self.notifications: notification.send(message) # Polymorphism - each type handles differently
# Usageservice = NotificationService()service.add_notification(SMSNotification("+1234567890"))service.add_notification(PushNotification("device-123"))
# All notifications work the same wayservice.broadcast("Your order has been shipped!")// Base notification classpublic abstract class Notification { public abstract boolean send(String message);}
public class EmailNotification extends Notification { private String recipient;
public EmailNotification(String recipient) { this.recipient = recipient; }
@Override public boolean send(String message) { // Email-specific implementation System.out.println("Sending email to " + recipient + ": " + message); return true; }}
public class SMSNotification extends Notification { private String phoneNumber;
public SMSNotification(String phoneNumber) { this.phoneNumber = phoneNumber; }
@Override public boolean send(String message) { // SMS-specific implementation String truncated = message.length() > 50 ? message.substring(0, 50) + "..." : message; System.out.println("Sending SMS to " + phoneNumber + ": " + truncated); return true; }}
public class PushNotification extends Notification { private String deviceId;
public PushNotification(String deviceId) { this.deviceId = deviceId; }
@Override public boolean send(String message) { // Push notification-specific implementation System.out.println("Sending push to device " + deviceId + ": " + message); return true; }}
// Service that can use any notification typepublic class NotificationService { private java.util.List<Notification> notifications;
public NotificationService() { this.notifications = new java.util.ArrayList<>(); }
public void addNotification(Notification notification) { // Add any notification type notifications.add(notification); }
public void broadcast(String message) { // Send message through all notification channels for (Notification notification : notifications) { notification.send(message); // Polymorphism - each type handles differently } }}
// Usagepublic class Main { public static void main(String[] args) { NotificationService service = new NotificationService(); service.addNotification(new SMSNotification("+1234567890")); service.addNotification(new PushNotification("device-123"));
// All notifications work the same way service.broadcast("Your order has been shipped!"); }}// Base notification classabstract class Notification { abstract send(message: string): boolean;}
class EmailNotification extends Notification { constructor(private recipient: string) { super(); }
send(message: string): boolean { console.log(`Sending email to ${this.recipient}: ${message}`); return true; }}
class SMSNotification extends Notification { constructor(private phoneNumber: string) { super(); }
send(message: string): boolean { const truncated = message.length > 50 ? message.substring(0, 50) + "..." : message; console.log(`Sending SMS to ${this.phoneNumber}: ${truncated}`); return true; }}
class PushNotification extends Notification { constructor(private deviceId: string) { super(); }
send(message: string): boolean { console.log(`Sending push to device ${this.deviceId}: ${message}`); return true; }}
class NotificationService { private notifications: Notification[] = [];
addNotification(notification: Notification): void { this.notifications.push(notification); }
broadcast(message: string): void { for (const notification of this.notifications) { notification.send(message); // Polymorphism - each type handles differently } }}
// Usageconst service = new NotificationService();service.addNotification(new SMSNotification("+1234567890"));service.addNotification(new PushNotification("device-123"));
service.broadcast("Your order has been shipped!");#include <iostream>#include <string>#include <vector>#include <memory>
// Base notification classclass Notification {public: virtual bool send(const std::string& message) = 0; virtual ~Notification() = default;};
class EmailNotification : public Notification {private: std::string recipient;
public: EmailNotification(const std::string& recipient) : recipient(recipient) {}
bool send(const std::string& message) override { std::cout << "Sending email to " << recipient << ": " << message << std::endl; return true; }};
class SMSNotification : public Notification {private: std::string phoneNumber;
public: SMSNotification(const std::string& phoneNumber) : phoneNumber(phoneNumber) {}
bool send(const std::string& message) override { std::string truncated = message.length() > 50 ? message.substr(0, 50) + "..." : message; std::cout << "Sending SMS to " << phoneNumber << ": " << truncated << std::endl; return true; }};
class PushNotification : public Notification {private: std::string deviceId;
public: PushNotification(const std::string& deviceId) : deviceId(deviceId) {}
bool send(const std::string& message) override { std::cout << "Sending push to device " << deviceId << ": " << message << std::endl; return true; }};
class NotificationService {private: std::vector<std::shared_ptr<Notification>> notifications;
public: void addNotification(std::shared_ptr<Notification> notification) { notifications.push_back(notification); }
void broadcast(const std::string& message) { for (const auto& notification : notifications) { notification->send(message); // Polymorphism - each type handles differently } }};
int main() { NotificationService service; service.addNotification(std::make_shared<SMSNotification>("+1234567890")); service.addNotification(std::make_shared<PushNotification>("device-123"));
service.broadcast("Your order has been shipped!");
return 0;}using System;using System.Collections.Generic;
// Base notification classpublic abstract class Notification{ public abstract bool Send(string message);}
public class EmailNotification : Notification{ private string recipient;
public EmailNotification(string recipient) { this.recipient = recipient; }
public override bool Send(string message) { Console.WriteLine($"Sending email to {recipient}: {message}"); return true; }}
public class SMSNotification : Notification{ private string phoneNumber;
public SMSNotification(string phoneNumber) { this.phoneNumber = phoneNumber; }
public override bool Send(string message) { string truncated = message.Length > 50 ? message.Substring(0, 50) + "..." : message; Console.WriteLine($"Sending SMS to {phoneNumber}: {truncated}"); return true; }}
public class PushNotification : Notification{ private string deviceId;
public PushNotification(string deviceId) { this.deviceId = deviceId; }
public override bool Send(string message) { Console.WriteLine($"Sending push to device {deviceId}: {message}"); return true; }}
public class NotificationService{ private List<Notification> notifications = new List<Notification>();
public void AddNotification(Notification notification) { notifications.Add(notification); }
public void Broadcast(string message) { foreach (var notification in notifications) { notification.Send(message); // Polymorphism - each type handles differently } }}
class Program{ static void Main() { NotificationService service = new NotificationService(); service.AddNotification(new SMSNotification("+1234567890")); service.AddNotification(new PushNotification("device-123"));
service.Broadcast("Your order has been shipped!"); }}package main
import ( "fmt")
type Notification interface { Send(message string) bool}
type EmailNotification struct{ Recipient string }
func (e *EmailNotification) Send(msg string) bool { fmt.Printf("Sending email to %s: %s\n", e.Recipient, msg) return true}
type SMSNotification struct{ Phone string }
func (s *SMSNotification) Send(msg string) bool { if len(msg) > 50 { msg = msg[:50] + "..." } fmt.Printf("Sending SMS to %s: %s\n", s.Phone, msg) return true}
type PushNotification struct{ Device string }
func (p *PushNotification) Send(msg string) bool { fmt.Printf("Sending push to device %s: %s\n", p.Device, msg) return true}
type NotificationSvc struct { Channels []Notification}
func (n *NotificationSvc) Add(ch Notification) { n.Channels = append(n.Channels, ch) }
func (n *NotificationSvc) Broadcast(msg string) { for _, ch := range n.Channels { _ = ch.Send(msg) }}
func main() { svc := &NotificationSvc{} svc.Add(&SMSNotification{"+1234567890"}) svc.Add(&PushNotification{"device-123"}) svc.Broadcast("Your order has been shipped!")}trait Notification { fn send(&self, message: &str) -> bool;}
struct EmailNotification { recipient: String,}
impl Notification for EmailNotification { fn send(&self, message: &str) -> bool { println!("Sending email to {}: {}", self.recipient, message); true }}
struct SmsNotification { phone: String,}
impl Notification for SmsNotification { fn send(&self, message: &str) -> bool { let message = if message.len() > 50 { format!("{}...", &message[..50]) } else { message.to_string() }; println!("Sending SMS to {}: {}", self.phone, message); true }}
struct PushNotification { device: String,}
impl Notification for PushNotification { fn send(&self, message: &str) -> bool { println!("Sending push to device {}: {}", self.device, message); true }}
struct NotificationSvc { channels: Vec<Box<dyn Notification>>,}
impl NotificationSvc { fn add(&mut self, channel: Box<dyn Notification>) { self.channels.push(channel); }
fn broadcast(&self, message: &str) { for channel in &self.channels { channel.send(message); } }}
fn main() { let mut svc = NotificationSvc { channels: vec![] }; svc.add(Box::new(EmailNotification { })); svc.add(Box::new(SmsNotification { phone: "+1234567890".into(), })); svc.add(Box::new(PushNotification { device: "device-123".into(), })); svc.broadcast("Your order has been shipped!");}Benefits of Polymorphism
Section titled “Benefits of Polymorphism”- Code Reusability - Write code once, use with multiple types
- Flexibility - Easy to add new types without changing existing code
- Maintainability - Changes to one type don’t affect others
- Simplicity - One interface for multiple implementations
- Extensibility - Easy to extend functionality
Key Takeaways
Section titled “Key Takeaways”Polymorphism is about flexibility - writing code that works with multiple types without knowing the specific type at compile time. It’s one of the most powerful features of object-oriented programming.