Start learning free

LESSON 181 OF 343 · OBJECT-ORIENTED PROGRAMMING

Inheritance in C++: Deriving a Class with public

Lesson Read the full explanation

TL ; DR:

A child class can inherit from a parent class — it gets all the parent's fields and methods for free, and can add its own. This lets you reuse code instead of copy-pasting it.


class Puppy : public Dog {
public:
    Puppy(string name) : Dog(name) {}
    void whine() { cout << "whimper" << endl; }
};


Full lesson:

Inheritance is one of the four classic OOP pillars (along with encapsulation, polymorphism, and abstraction). The idea is simple: most real-world things are kinds of other things — a Puppy is a Dog, a Car is a Vehicle, a Manager is an Employee. When you model that "is-a" relationship in code, the child class gets the parent's data and behavior automatically.

What gets inherited?

  • Fields — the Puppy has a name field even though we only declared it on Dog.
  • Methods — the Puppy can call bark() even though we only defined it on Dog.
  • The contract — anywhere code expects a Dog, you can pass a Puppy (we'll see this when we cover polymorphism).

What you still write

  • The constructor usually has to forward arguments up to the parent's constructor (because the parent's fields need initializing).
  • Any new methods or new fields specific to the child.

Your task

Below the Dog class, create a Puppy class that inherits from Dog and adds one new method, whine(), that prints "whimper". The harness creates a Puppy named "Buddy", calls its inherited bark(), and then its new whine().

Expected output:

Woof! I am Buddy
whimper
STEP 1 OF 2
    Ctrl + Enter to check

    C++ · OBJECT-ORIENTED PROGRAMMING

    Inheritance in C++, explained

    The is-a relationship

    Many things are specialized kinds of other things: a puppy is a dog, a car is a vehicle, a manager is an employee. Inheritance lets a class say so in code. A derived class (the child) is built on a base class (the parent) and automatically gets the base class's members. It can add members of its own, so you don't copy and paste code between related classes.

    C++ also supports a class with several bases, but this lesson covers the common case of one.

    Syntax

    After the new class name, write a colon, an access keyword and the base class:

    class Puppy : public Dog {
    public:
        Puppy(string name) : Dog(name) {}
        void whine() { cout << "whimper" << endl; }
    };
    

    The keyword public before Dog means the base class's public members stay public in Puppy. It is what you want for an is-a relationship. If you leave it out, a class inherits privately by default, and the base's members become inaccessible from outside. A call such as buddy.bark() then fails with an error saying the function is inaccessible. A struct inherits publicly by default.

    What a derived class receives

    • Member variables. A Puppy has a name even though only Dog declares it.
    • Member functions. A Puppy can call bark() though only Dog defines it.
    • Substitutability. Wherever code expects a Dog reference or pointer, a Puppy can be passed. The polymorphism lesson builds on this.

    Private members of the base are part of the derived object, but the derived class's code can't name them. If a child needs access, make the member protected in the base.

    Forwarding the constructor

    Constructors are not inherited. Each class has its own, and creating a Puppy builds the Dog part first and the Puppy part after. The base part must be built with arguments if the base's constructor needs them. That call is written in the derived constructor's initializer list, after a colon:

    Puppy(string name) : Dog(name) {}
    

    This reads: to build a Puppy from a name, first build its Dog part from that name, then run the body, which is empty here. The call goes before the body because the base part must exist before the derived constructor's own code touches it.

    In this lesson, Dog has only Dog(string name), so it has no default constructor, and the compiler can't guess what to pass. Without the forwarding constructor, Puppy buddy("Buddy"); fails with no matching function for call to 'Puppy::Puppy(const char [6])'.

    Destruction runs the other way around. If both classes print in their constructors and destructors, creating a puppy shows the Dog constructor, then the Puppy constructor, and at the end of the scope the Puppy destructor and then the Dog destructor.

    The lesson's exercise

    The Dog class is given, with name, a constructor and bark(). The task is to write a Puppy class below it, so that the code in mainFunction prints:

    Woof! I am Buddy
    whimper
    1. Declare class Puppy : public Dog and open a public: section. Members of a class are private by default, and mainFunction needs to create a Puppy and call its functions.
    2. Add a one-line constructor Puppy(string name) : Dog(name) {}.
    3. Add void whine(), which prints "whimper" followed by endl. Nothing is needed for bark, since it's inherited.
    4. Close the class with };. The class must sit below Dog, since the base must be fully defined before it is used.

    The solution in C++

    class Dog {
    public:
        string name;
        Dog(string name) { this->name = name; }
        void bark() {
            cout << "Woof! I am " << name << endl;
        }
    };
    
    class Puppy : public Dog {
    public:
        Puppy(string name) : Dog(name) {}
        void whine() {
            cout << "whimper" << endl;
        }
    };
    
    class Solution {
    public:
        void mainFunction() {
            Puppy buddy("Buddy");
            buddy.bark();
            buddy.whine();
        }
    };
    

    In Puppy(string name) : Dog(name) {}, the parameter is called name, the same as the base member. In the initializer list, Dog(name) uses the parameter, so the name travels up to the base, which stores it in its own member. The empty braces are the whole body, because the base constructor already did the work.

    Common mistakes

    • Omitting public in : public Dog. The code then fails because bark() becomes inaccessible from outside.
    • Not forwarding the arguments. If the base has no default constructor, the derived constructor must call a base constructor explicitly.
    • Trying to assign the base members in the body instead of calling Dog(name). The base part is built before the body runs, and with no way to build it, the code does not compile.
    • Forgetting the semicolon after the closing brace of Puppy.
    • Re-declaring name in Puppy. That creates a second, separate member, which is not what you want.
    • Copying a Puppy into a Dog variable. Dog d = buddy; compiles, but only the Dog part is copied. This is called slicing.

    Key takeaways

    • class Child : public Parent gives the child the parent's public members and lets it add its own.
    • Constructors are not inherited; call the parent's in the initializer list.
    • The base part is constructed first and destroyed last.
    • Use inheritance for real is-a relationships, not just to reuse code.
    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free