Inheritance
Inheritance lets a new class start from an existing one. The new class (the derived class) gets everything the base class has, then adds or changes what it needs. A Dog is an Animal, so it can eat like any animal, and it can fetch as well.
Deriving a class
#include <iostream>
#include <string>
using namespace std;
class Animal {
public:
string name;
void eat() const { cout << name << " is eating" << endl; }
};
class Dog : public Animal { // a Dog is an Animal
public:
void fetch() const { cout << name << " fetches the ball" << endl; }
};
int main() {
Dog d;
d.name = "Rex"; // inherited from Animal
d.eat(); // inherited
d.fetch(); // Dog's own
return 0;
}Rex is eating
Rex fetches the ballclass Dog : public Animal means Dog inherits Animal's members, and everyone may treat a Dog as an Animal. (public inheritance is the kind you'll use almost always.)
Base constructors and protected members
#include <iostream>
#include <string>
using namespace std;
class Employee {
protected: // visible to derived classes, hidden from everyone else
string name;
double salary;
public:
Employee(const string& n, double s) : name(n), salary(s) {}
void describe() const { cout << name << " earns " << salary << endl; }
};
class Manager : public Employee {
int reports;
public:
Manager(const string& n, double s, int r) : Employee(n, s), reports(r) {}
void describeTeam() const {
cout << name << " manages " << reports << " people" << endl;
}
};
int main() {
Manager m("Asha", 95000, 6);
m.describe();
m.describeTeam();
return 0;
}Asha earns 95000
Asha manages 6 people- A derived class builds its base part first, so
Manager's initializer list starts by callingEmployee(n, s). protectedsits betweenpublicandprivate: derived classes can use the member, outside code can't. Ifnamewere private,describeTeamcouldn't read it.
Construction and destruction order
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base built" << endl; }
~Base() { cout << "Base destroyed" << endl; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived built" << endl; }
~Derived() { cout << "Derived destroyed" << endl; }
};
int main() {
Derived d;
cout << "using d" << endl;
return 0;
}Base built
Derived built
using d
Derived destroyed
Base destroyedThe base is built first, because the derived part may rely on it, and destroyed last: the reverse order, like a stack of plates.
Redefining a function
#include <iostream>
#include <string>
using namespace std;
class Shape {
public:
string describe() const { return "a shape"; }
};
class Circle : public Shape {
public:
string describe() const { return "a circle, which is " + Shape::describe(); }
};
int main() {
Circle c;
cout << c.describe() << endl;
Shape& s = c; // a Circle used through a Shape reference
cout << s.describe() << endl;
return 0;
}a circle, which is a shape
a shapeA derived class can define a function with the same name as one in its base. Shape::describe() still reaches the base version.
Look at the last line, though. s refers to a Circle, yet s.describe() ran Shape's version, because without extra help C++ picks the function from the reference's type, Shape&, not from the object's real type. Making it pick the real type is what virtual functions are for, in the next lesson.
Is it really "is a"?
Inherit only when the derived class truly is a kind of the base: a Manager is an Employee, a Circle is a Shape. When one thing merely has another (a car has an engine), make it a member instead. That's called composition, and it's usually the better choice.