"is-a":
Foo is-a Bar :
class Foo : public Bar
"has-a"
Foo has-a Bar
class Foo
{
private:
Bar b;
};
If you write that class D publicly inherits from class B(Base), you are telling C++ compilers that every object of type D is also an object of type B. You are saying that B represents a more general concept than D, that D represents a more specialized concept than B. Anywhere an object of type B can be used, an object of type D can be used as well. It is actually a is-a model.
For example, we know that every student is a person, but not every person is a student. Within the realm of C++, any function that expects an argument of type Person will also take a Student object :
void eat(const Person& p);
void study(const Student& s);
Person p;
Student s;
eat(p);
eat(s);
study(s);
study(p); // error!
This is true only for public inheritance. C++ will behave what we said before only if Student is publicly derived from Person, Private inheritance means something entirely different, and protected inheritance is something whose meaning eludes me to this day.
The equivalence of public inheritance and is-a sounds simple, but sometimes your intuition can mislead you. For example, it is a fact that a penguin is a bird, and it is a fact that birds can fly. If we natively try to express this in C++, our effort yields :
class Bird{
public:
virtual void fly();
...
};
class Penguin : public Bird{
...
};
Suddenly we are in trouble, because this hierarchy says that penguins can fly, which we know is not true. What happened?
This is the problem that means "All birds can fly, penguins are birds, penguins can't fly !" . That is to redefine the fly function for penguin so that it generates a runtime error :
void error(const std::string& msg);
class Penguin : public Bird
{
public:
virtual void fly() {error(",,,");}
};
Actually, what is this program saying is that penguins try to fly , but it can't. We know that it says this in the runtime, however, what we want is that we get a message that penguins can't fly, which means that we should get the message while compiling.
To express the constraint, "Penguins can't fly -- period", you make sure that no such function is defined for Penguin objects:
class Bird{
... // no fly function is declared
};
class Penguin : public Bird{
... // no fly function is declared
};
It you now try to make a penguin fly, compilers will reprimand you for your transgression :
Penguin p;
p.fly(); // error!
Conclusion
- Public inheritance means "is-a." Everything that applies to base classes must also apply to derived classes, because every derived class object is a base class object.