Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. C++ Dictionary
  3. polymorphism

polymorphism

Polymorphism (dynamic dispatch) is the ability to call derived class methods through a base class pointer or reference. In C++, you declare virtual functions using the virtual keyword on the base class, and the appropriate derived class method is selected at runtime through a mechanism called dynamic dispatch.

Syntax

// ========================================
// Polymorphism basics
// ========================================

// Define a virtual function on the base class with the virtual keyword
class Base {
public:
    virtual void method() {
        // base class implementation
    }

    // Virtual destructor — ensures the derived class destructor is called on delete
    virtual ~Base() {}
};

// Override in the derived class using the override keyword (C++11 and later)
class Derived : public Base {
public:
    void method() override {
        // derived class implementation
    }
};

// Calling a virtual function through a base class pointer invokes the derived implementation
Base* obj = new Derived();
obj->method();  // Derived::method() is called (dynamic dispatch)
delete obj;

// dynamic_cast for safe downcasting
Derived* d = dynamic_cast<Derived*>(obj);
if (d != nullptr) {
    // downcast succeeded
}

Syntax Reference

Syntax / KeywordDescription
virtual void f()Declares a virtual function. When called through a base class pointer, the derived class implementation is selected.
void f() overrideOverrides a virtual function in a derived class. The override keyword (C++11+) causes a compile error if no matching virtual function exists in the base class.
virtual ~Base()Declares a virtual destructor. Ensures the derived class destructor is called when deleting through a base class pointer.
Dynamic dispatchAt runtime the virtual function table (vtable) is consulted and the method matching the actual object type is called.
dynamic_cast<T*>(ptr)Safe downcast using runtime type information (RTTI). Returns nullptr on failure (pointer version) or throws std::bad_cast (reference version).

Sample Code

yakuza_polymorphism.cpp
// ========================================
// yakuza_polymorphism.cpp
// Demonstrates polymorphism using a class
// hierarchy based on Yakuza (Like a Dragon)
// characters
// ========================================

#include <iostream>
#include <string>
#include <vector>

// ========================================
// Base class: Fighter (common interface)
// ========================================
class Fighter {
protected:
    std::string name;
    int hp;

public:
    Fighter(const std::string& name, int hp) : name(name), hp(hp) {}

    // virtual keyword makes this a virtual function (overridable in derived classes)
    virtual void attack() {
        std::cout << name << " attacks." << std::endl;
    }

    // Virtual functions can be left as-is to use the default implementation
    virtual void introduce() {
        std::cout << "Name: " << name << "  HP: " << hp << std::endl;
    }

    // A virtual destructor is required.
    // Without it, the derived class destructor is not called when deleting
    // through a base class pointer.
    virtual ~Fighter() {
        std::cout << name << " destructor called." << std::endl;
    }
};

// ========================================
// Derived class: KiryuKazuma
// ========================================
class KiryuKazuma : public Fighter {
public:
    KiryuKazuma() : Fighter("Kiryu Kazuma", 9999) {}

    // override keyword verifies that a matching virtual function exists in the base class
    void attack() override {
        std::cout << name << " activates \"Dragon of Dojima\"! Delivers a powerful punch." << std::endl;
    }
};

// ========================================
// Derived class: MajimaGoro
// ========================================
class MajimaGoro : public Fighter {
public:
    MajimaGoro() : Fighter("Majima Goro", 8500) {}

    void attack() override {
        std::cout << name << " activates \"Mad Dog of Shimano\"! Unleashes a flurry of knife strikes." << std::endl;
    }
};

// ========================================
// Derived class: AkiyamaShun
// ========================================
class AkiyamaShun : public Fighter {
public:
    AkiyamaShun() : Fighter("Akiyama Shun", 7800) {}

    void attack() override {
        std::cout << name << " lands \"Brawler Kick\"! Sends the opponent flying with a flying kick." << std::endl;
    }
};

// ========================================
// Receives a base class pointer — dynamic dispatch selects the correct attack()
// ========================================
void battleScene(Fighter* fighter) {
    fighter->introduce();
    fighter->attack();
    std::cout << std::endl;
}

int main() {
    // Store derived class instances in a base class pointer array
    std::vector<Fighter*> party;
    party.push_back(new KiryuKazuma());
    party.push_back(new MajimaGoro());
    party.push_back(new AkiyamaShun());

    std::cout << "=== Battle Scene ===" << std::endl << std::endl;

    // Calling through Fighter* invokes each derived class's attack() — this is polymorphism
    for (int i = 0; i < (int)party.size(); i++) {
        battleScene(party[i]);
    }

    // dynamic_cast checks whether a pointer points to a specific derived type
    std::cout << "=== dynamic_cast demo ===" << std::endl;
    Fighter* unknown = party[0];
    KiryuKazuma* kiryu = dynamic_cast<KiryuKazuma*>(unknown);
    if (kiryu != nullptr) {
        std::cout << "This character is Kiryu Kazuma." << std::endl;
    }

    std::cout << std::endl << "=== Cleanup ===" << std::endl;

    // The virtual destructor ensures derived class destructors are called correctly
    for (int i = 0; i < (int)party.size(); i++) {
        delete party[i];
    }

    return 0;
}
g++ -std=c++11 yakuza_polymorphism.cpp -o yakuza_polymorphism
./yakuza_polymorphism
=== Battle Scene ===

Name: Kiryu Kazuma  HP: 9999
Kiryu Kazuma activates "Dragon of Dojima"! Delivers a powerful punch.

Name: Majima Goro  HP: 8500
Majima Goro activates "Mad Dog of Shimano"! Unleashes a flurry of knife strikes.

Name: Akiyama Shun  HP: 7800
Akiyama Shun lands "Brawler Kick"! Sends the opponent flying with a flying kick.

=== dynamic_cast demo ===
This character is Kiryu Kazuma.

=== Cleanup ===
Kiryu Kazuma destructor called.
Majima Goro destructor called.
Akiyama Shun destructor called.

Common mistake 1: Missing virtual destructor in the base class

When deleting through a base class pointer, if the destructor is not virtual the derived class destructor is not called, potentially causing resource leaks.

// NG:
class Base {
public:
    ~Base() {}  // not virtual — derived class destructor will not be called
};

class Derived : public Base {
public:
    ~Derived() { /* resource cleanup */ }
};

Base* obj = new Derived();
delete obj;  // Derived::~Derived() is not called (resource leak risk)

OK: Add virtual to the base class destructor.

// OK:
class Base {
public:
    virtual ~Base() {}  // virtual ensures the derived destructor is always called
};

Common mistake 2: Typo in function signature without the override keyword

Without override, a mismatched function signature silently defines a new function instead of overriding the virtual one. The expected dynamic dispatch does not occur and the bug may be hard to find.

// NG:
class Fighter {
public:
    virtual void attack(int power) {}
};

class KiryuKazuma : public Fighter {
public:
    void attack() {}  // different signature — defines a new function, not an override
};

OK: Use override so the compiler catches signature mismatches.

// OK:
class KiryuKazuma : public Fighter {
public:
    void attack(int power) override {}  // correct signature with override
};

Overview

Polymorphism lets you call derived-class-specific behavior through a base class pointer or reference and is a cornerstone of object-oriented design. In C++, functions marked with virtual become virtual functions; at runtime the vtable is consulted and the method corresponding to the actual object type is selected. When overriding in a derived class, the override keyword (C++11+) is often used to catch signature mismatches at compile time. When deleting objects through a base class pointer, the base class must have a virtual destructor (virtual ~Base()); without it, the derived class destructor is not called and resources may leak. dynamic_cast performs a safe downcast using runtime type information (RTTI), but heavy use may indicate a design worth revisiting from an open/closed principle perspective.

If you find any errors or copyright issues, please .