← SEARCHABLE ARCHIVE
C / C++ · 2026-06-12

C++ from Basics to Mastery — Part 8

Inheritance and polymorphism, object lifetime and RAII

INTERACTIVE READING MODE →

The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.

Warrior and Archer are both characters, but their attack methods are different. Common data can be placed in the parent class, and different operations can be implemented in the child class.

Inheritance and Polymorphism

class Character
{
public:
    Character(const std::string& name)
        : name(name)
    {
    }

    virtual ~Character() = default;
    virtual int Attack() const = 0;

    const std::string& GetName() const
    {
        return name;
    }

private:
    std::string name;
};

class Warrior : public Character
{
public:
    Warrior(const std::string& name)
        : Character(name)
    {
    }

    int Attack() const override
    {
        return 20;
    }
};

class Archer : public Character
{
public:
    Archer(const std::string& name)
        : Character(name)
    {
    }

    int Attack() const override
    {
        return 15;
    }
};

Attack() = 0A class with pure virtual functions without implementation becomes an abstract class. The Character itself cannot be created, and child classes are forced to implement Attack.

overrideIf you add , the compiler catches an error when the signature is different from the parent function's signature. This can prevent mistakes that result in a new function being treated as a spelling error.

Even if you call Attack with the parent pointer, different functions are executed depending on whether the actual object is Warrior or Archer. This is runtime polymorphism.

virtual destructor

It is safe to leave the destructor of the parent class for inheritance virtual.

virtual ~Character() = default;

When deleting a child object through the parent pointer, if there is no virtual destructor, the child destructor may not be called. If the child is holding resources such as files or memory, cleanup may be missed.

Object lifetime and RAII

Local objects are automatically destroyed at the end of a block.

void Battle()
{
    Warrior warrior{"Rose"};
    std::cout << warrior.Attack() << '\n';
} //Here, warrior's destructor is called.

The method that links object creation and resource acquisition, and object destruction and resource release, is called RAII. Even if a return is made in the middle of the function, the destructor of the local object is called.

good night. You can now tell who organizes what and when by just looking at the code. on the other waynewanddeleteIf they are scattered all over the place, it becomes difficult to know who owns them.

Objects that require polymorphism should not be stored as values ​​in the parent type. std::vector<Character>Entering Warrior as a value may result in object slicing where child parts are cut off.

Therefore, it must be stored in pointer form as follows.

std::vector<std::unique_ptr<Character>> party;

Now we need smart pointers that allow pointers to automatically clean up objects while owning them.