[2026] C++ Inheritance & Polymorphism: virtual, Interfaces, and Patterns

[2026] C++ Inheritance & Polymorphism: virtual, Interfaces, and Patterns

이 글의 핵심

C++ inheritance and polymorphism: public inheritance, virtual functions, abstract classes, virtual destructors, slicing, template method, and composition vs inheritance.

What are inheritance and polymorphism?

Inheritance reuses attributes and methods from an existing class. Polymorphism lets you treat different types through the same interface. Why they matter:

  • Reuse: shared behavior in a base class
  • Extensibility: add new types easily
  • Flexibility: choose behavior at runtime
  • Abstraction: separate interface from implementation 다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// Without inheritance: duplication
// 타입 정의
class Dog {
    string name;
public:
    void eat() { cout << name << " eats\n"; }
    void bark() { cout << "woof\n"; }
};
class Cat {
    string name;
public:
    void eat() { cout << name << " eats\n"; }  // duplicated
    void meow() { cout << "meow\n"; }
};
// With inheritance: reuse
class Animal {
protected:
    string name;
public:
    Animal(string n) : name(n) {}
    void eat() { cout << name << " eats\n"; }
};
class Dog : public Animal {
public:
    Dog(string n) : Animal(n) {}
    void bark() { cout << "woof\n"; }
};

Inheritance structure: 아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TD
    Animal["Animal (base)"]
    Dog["Dog (derived)"]
    Cat["Cat (derived)"]
    
    Animal --> Dog
    Animal --> Cat
    
    Animal -.-> |eat| A1[eat()]
    Dog -.-> |bark| D1[bark()]
    Cat -.-> |meow| C1[meow()]

Basic inheritance

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Animal {
protected:
    string name;
    
public:
    Animal(string n) : name(n) {}
    
    void eat() {
        cout << name << " is eating" << endl;
    }
};
class Dog : public Animal {
public:
    Dog(string n) : Animal(n) {}
    
    void bark() {
        cout << name << " barks: woof!" << endl;
    }
};
int main() {
    Dog dog("Rex");
    dog.eat();   // inherited
    dog.bark();  // Dog-only
}

Access specifiers:

Inheritancepublic memberprotected memberprivate member
publicpublicprotectedinaccessible
protectedprotectedprotectedinaccessible
privateprivateprivateinaccessible
다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
class Base {
public:
    int pub;
protected:
    int prot;
private:
    int priv;
};
class Derived : public Base {
    void func() {
        pub = 1;   // OK
        prot = 2;  // OK
        // priv = 3;  // error
    }
};

virtual functions and polymorphism

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Animal {
public:
    virtual void speak() {
        cout << "animal sound" << endl;
    }
};
class Dog : public Animal {
public:
    void speak() override {
        cout << "woof!" << endl;
    }
};
class Cat : public Animal {
public:
    void speak() override {
        cout << "meow!" << endl;
    }
};
int main() {
    Animal* animals[3];
    animals[0] = new Animal();
    animals[1] = new Dog();
    animals[2] = new Cat();
    
    for (int i = 0; i < 3; i++) {
        animals[i]->speak();
    }
    
    for (int i = 0; i < 3; i++) {
        delete animals[i];
    }
}

Abstract classes (pure virtual)

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Shape {
public:
    virtual double area() = 0;
    virtual double perimeter() = 0;
    virtual ~Shape() {}
};
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r) : radius(r) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
    
    double perimeter() override {
        return 2 * 3.14159 * radius;
    }
};
class Rectangle : public Shape {
private:
    double width, height;
    
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double area() override {
        return width * height;
    }
    
    double perimeter() override {
        return 2 * (width + height);
    }
};
int main() {
    Shape* shapes[2];
    shapes[0] = new Circle(5.0);
    shapes[1] = new Rectangle(4.0, 6.0);
    
    for (int i = 0; i < 2; i++) {
        cout << "area: " << shapes[i]->area() << endl;
        delete shapes[i];
    }
}

Practical examples

Example 1: Game characters

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Character {
protected:
    string name;
    int hp;
    int attackPower;
    
public:
    Character(string n, int h, int ap) 
        : name(n), hp(h), attackPower(ap) {}
    
    virtual ~Character() {}
    
    virtual void attack(Character* target) {
        cout << name << " attacks!" << endl;
        target->takeDamage(attackPower);
    }
    
    virtual void takeDamage(int damage) {
        hp -= damage;
        cout << name << " took " << damage << " damage (HP: " << hp << ")" << endl;
    }
    
    virtual void useSkill() = 0;
    
    bool isAlive() { return hp > 0; }
    string getName() { return name; }
};
class Warrior : public Character {
public:
    Warrior(string n) : Character(n, 150, 30) {}
    
    void useSkill() override {
        cout << name << " uses Strike!" << endl;
        attackPower += 20;
    }
};
class Mage : public Character {
public:
    Mage(string n) : Character(n, 80, 50) {}
    
    void useSkill() override {
        cout << name << " casts Fireball!" << endl;
        attackPower += 30;
    }
};
class Healer : public Character {
public:
    Healer(string n) : Character(n, 100, 15) {}
    
    void useSkill() override {
        cout << name << " heals!" << endl;
        hp += 50;
        cout << "HP restored (now " << hp << ")" << endl;
    }
};
int main() {
    vector<Character*> party;
    party.push_back(new Warrior("Warrior"));
    party.push_back(new Mage("Mage"));
    party.push_back(new Healer("Healer"));
    
    for (auto& character : party) {
        character->useSkill();
    }
    
    for (auto& character : party) {
        delete character;
    }
    
    return 0;
}

Polymorphism lets one container hold different character types behind a common Character* interface.

Example 2: Payment system

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <string>
using namespace std;
class PaymentMethod {
public:
    virtual bool pay(double amount) = 0;
    virtual string getMethodName() = 0;
    virtual ~PaymentMethod() {}
};
class CreditCard : public PaymentMethod {
private:
    string cardNumber;
    
public:
    CreditCard(string num) : cardNumber(num) {}
    
    bool pay(double amount) override {
        cout << "Credit card payment: " << amount << " KRW" << endl;
        cout << "Card: " << cardNumber << endl;
        return true;
    }
    
    string getMethodName() override {
        return "Credit card";
    }
};
class BankTransfer : public PaymentMethod {
private:
    string accountNumber;
    
public:
    BankTransfer(string acc) : accountNumber(acc) {}
    
    bool pay(double amount) override {
        cout << "Bank transfer: " << amount << " KRW" << endl;
        cout << "Account: " << accountNumber << endl;
        return true;
    }
    
    string getMethodName() override {
        return "Bank transfer";
    }
};
class PaymentProcessor {
public:
    void processPayment(PaymentMethod* method, double amount) {
        cout << "\n=== Payment ===" << endl;
        cout << "Method: " << method->getMethodName() << endl;
        
        if (method->pay(amount)) {
            cout << "Success!" << endl;
        } else {
            cout << "Failed!" << endl;
        }
    }
};
int main() {
    PaymentProcessor processor;
    
    CreditCard card("1234-5678-9012-3456");
    processor.processPayment(&card, 50000);
    
    BankTransfer transfer("123-456-789012");
    processor.processPayment(&transfer, 30000);
    
    return 0;
}

Example 3: Document formats

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <string>
using namespace std;
class Document {
protected:
    string content;
    
public:
    Document(string c) : content(c) {}
    virtual ~Document() {}
    
    virtual void save(const string& filename) = 0;
    virtual string getFormat() = 0;
};
class PDFDocument : public Document {
public:
    PDFDocument(string c) : Document(c) {}
    
    void save(const string& filename) override {
        cout << "Save as PDF: " << filename << ".pdf" << endl;
        cout << "Content: " << content << endl;
    }
    
    string getFormat() override {
        return "PDF";
    }
};
class WordDocument : public Document {
public:
    WordDocument(string c) : Document(c) {}
    
    void save(const string& filename) override {
        cout << "Save as Word: " << filename << ".docx" << endl;
        cout << "Content: " << content << endl;
    }
    
    string getFormat() override {
        return "Word";
    }
};
class DocumentConverter {
public:
    void convert(Document* doc, const string& filename) {
        cout << "\n=== Convert ===" << endl;
        cout << "Format: " << doc->getFormat() << endl;
        doc->save(filename);
    }
};
int main() {
    DocumentConverter converter;
    
    PDFDocument pdf("PDF body");
    converter.convert(&pdf, "report");
    
    WordDocument word("Word body");
    converter.convert(&word, "letter");
    
    return 0;
}

Common problems

Problem 1: Missing virtual destructor

Symptom: derived destructor never runs (leak).
Cause: base destructor is not virtual.
Fix: 다음은 간단한 cpp 코드 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

class Base {
public:
    virtual ~Base() { cout << "~Base" << endl; }
};

Problem 2: Missing override

Symptom: you meant to override but created a new function.
Cause: signature mismatch.
Fix: use override and match the base signature.

Problem 3: Slicing

Symptom: derived state is lost.
Cause: copy by value.
Fix: use pointers or references to base.

Patterns

Template method

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class DataProcessor {
public:
    void process() {
        loadData();
        validateData();
        transformData();
        saveData();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;
    virtual void validateData() {}
    virtual void transformData() = 0;
    virtual void saveData() = 0;
};
class CSVProcessor : public DataProcessor {
protected:
    void loadData() override { std::cout << "load CSV\n"; }
    void transformData() override { std::cout << "transform CSV\n"; }
    void saveData() override { std::cout << "save CSV\n"; }
};
CSVProcessor processor;
processor.process();

Interface segregation

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class IReadable {
public:
    virtual std::string read() = 0;
    virtual ~IReadable() = default;
};
class IWritable {
public:
    virtual void write(const std::string& data) = 0;
    virtual ~IWritable() = default;
};
class File : public IReadable, public IWritable {
public:
    std::string read() override { return "file content"; }
    void write(const std::string& data) override {
        std::cout << "write: " << data << '\n';
    }
};

Factory method

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Product {
public:
    virtual void use() = 0;
    virtual ~Product() = default;
};
class ConcreteProductA : public Product {
public:
    void use() override { std::cout << "Product A\n"; }
};
class ConcreteProductB : public Product {
public:
    void use() override { std::cout << "Product B\n"; }
};
class Creator {
public:
    virtual std::unique_ptr<Product> createProduct() = 0;
    virtual ~Creator() = default;
    
    void operation() {
        auto product = createProduct();
        product->use();
    }
};
class CreatorA : public Creator {
public:
    std::unique_ptr<Product> createProduct() override {
        return std::make_unique<ConcreteProductA>();
    }
};

FAQ

Q1: Are virtual functions slow?

A: Small overhead (vtable indirection); flexibility usually wins.

Q2: Make everything virtual?

A: No—only functions that need overriding. Destructors in polymorphic bases should be virtual.

Q3: Multiple inheritance?

A: Prefer sparingly; multiple interface inheritance is common; watch for the diamond problem.

Q4: override vs final?

A: override checks you really override; final stops further overrides.

Q5: Abstract class vs interface?

A: C++ has no interface keyword—use classes with only pure virtual functions as interfaces.

Q6: Inheritance vs composition?

A: is-a vs has-a; composition is often more flexible.

Q7: Why virtual destructor?

A: So deleting through Base* runs Derived::~Derived().

Q8: Resources?

A: Effective C++, C++ Primer, cppreference — derived class. One-line summary: Inheritance shares implementation; polymorphism dispatches to the right override through a common interface.

Practical tips

Debugging

  • Enable warnings

Performance

  • Profile first

Code review

  • Team conventions

Practical checklist

Before coding

  • Right tool?
  • Maintainable?
  • Meets performance goals?

While coding

  • Warnings clean?
  • Edge cases?
  • Error handling?

At review

  • Clear intent?
  • Tests?
  • Documentation?

Keywords

C++, inheritance, polymorphism, virtual, OOP

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3