Inheritance In Python & JavaScript Link to heading

So here’s a fun thing that bit me on my C++ learning journey. In my previous experience with Python, it was (relatively) common to set a property (or properties) on a base class, then make use of that property within the methods of that base class.

class Base:
    def __init__(self):
        self.some_int = 0

    def get_int(self):
        return self.some_int

For derived classes, we could simply override the property.

class Derived(Base):
    def __init__(self):
        self.some_int = 1

And the methods would use the “closest” some_int property in their results.

if __name__ == "__main__":
    foo = Base()
    bar = Derived()

    print("From foo:", foo.get_int())
    print("From bar:", bar.get_int())

    # Prints:
    # From foo: 0
    # From bar: 1

In ES6-flavored JavaScript, things work in a similar way.

class Base {
    constructor() {
        this.some_num = 0;
    }

    get_num() {
        return this.some_num;
    }
}

class Derived extends Base {
    constructor() {
        super();
        this.some_num = 1;
    }
}

const foo = new Base();
const bar = new Derived();

console.log("From foo:", foo.get_num());
console.log("From bar:", bar.get_num());

// Prints:
// From foo: 0
// From bar: 1

Inheritance In C++ - First Attempt Link to heading

In C++ things are a bit different. Let’s start with our base class one more time.

class Base {
    public:
        Base() : some_int_(0) {}

        int getInt() { return some_int_; }
    private:
        int some_int_;
};

I’ve tried my best to write “idiomatic” C++ code here, including the use of a private variable with a public getter. That aside, this should look pretty similar to the base classes from the Python & JavaScript examples.

Now, let’s construct our derived class.

class Derived : public Base {
    public:
        Derived() : some_int_(1) {}
    private:
        int some_int_;
};

Note here that we have to re-declare some_int_ within Derived, or else we get an error like the following:

main.cc:15:21: error: member initializer 'some_int_' does not name a non-static data member or base class
        Derived() : some_int_(1) {}

Finally, we put the whole thing together & run the program.

#include <stdio.h>

class Base {
    public:
        Base() : some_int_(0) {}
        int getInt() { return some_int_; }
    private:
        int some_int_;
};

class Derived : public Base {
    public:
        Derived() : some_int_(1) {}
    private:
        int some_int_;
};

int main() {
    Base foo = Base();
    Derived bar = Derived();

    printf("From foo: %d\n", foo.getInt());
    printf("From bar: %d\n", bar.getInt());
    return 0;

    // Prints:
    // From foo: 0
    // From bar: 0
}

Horsefeathers! Unfortunately, C++ diverges from Python & JavaScript on this pattern. When we call Derived::getInt(), we’re actually calling Base::getInt(), as the getInt method is not defined for the Derived class. Additionally if Derived inherits from Base, and they both define a member named some_int_, both of the variables exist independently at the same time (credit to this Stack Overflow post for the language there). This is in direct opposition to the way Python & JavaScript operate, where defining a member in a derived class essentially erases the base class’s definition of that member.

Inheritance In C++ - Second Attempt Link to heading

To make this sort of pattern work, we also have to re-declare the getInt method on the Derived class.

class Derived : public Base {
    public:
        Derived() : some_int_(1) {}
        int getInt() { return some_int_; } // <<<<
    private:
        int some_int_;

    // SNIP

    // Prints:
    // From foo: 0
    // From bar: 1

This forces Derived::getInt() to look “locally” for the some_int_ variable, which then returns the right value.

However! This doesn’t feel quite right to me. Aside from the duplication of code, it’s perhaps a bit too-contrived of an example.

Inheritance In C++ - Third Attempt Link to heading

Let’s revisit the idea of providing an explicit, parameterized constructor for the Base class. We’ll include some_int as an argument to this constructor.

class Base {
    public:
        Base() : some_int_(0) {}
        Base(int some_int) : some_int_(some_int) {}
        int getInt() { return some_int_; }
    private:
        int some_int_;
};

Note that we keep the zero-argument constructor for Base in place. This polymorphism-first pattern is (to me) one of the distinguishing characteristics of C++ versus the languages I’m more familiar with. After these changes we’ll call this new single-argument Base constructor within the zero-argument Derived constructor. We can also remove the re-declarations of both getInt and the some_int_ member variable.

class Derived : public Base {
    public:
        Derived() : Base(1) {}
};

Then, we put the whole thing together & run the program.

#include <stdio.h>

class Base {
    public:
        Base() : some_int_(0) {}
        Base(int some_int) : some_int_(some_int) {}
        int getInt() { return some_int_; }
    private:
        int some_int_;
};

class Derived : public Base {
    public:
        Derived() : Base(1) {}
};

int main() {
    Base foo = Base();
    Derived bar = Derived();

    printf("From foo: %d\n", foo.getInt());
    printf("From bar: %d\n", bar.getInt());
    return 0;

    // Prints:
    // From foo: 0
    // From bar: 1
}

Ahh, now that’s more like it! Though we’re still actually calling Base::getInt() when calling bar.getInt() in the example above, the underlying value is set appropriately because of the way we’ve written the constructors. The overall shape of the code ends up looking pretty darn similar, just with a subtle difference in where we do the variable “override” thanks to the polymorphic constructor on the Base class.