It’s all about delicious… PIE!

Don’t look at me that way, I’m not crazy. Pie really does have everything to do with OOP or Object-Oriented Programming.
It’s the conceptual base that makes C++ (and Java, Python, Ruby, Simula, etc) what they are, OOP languages. So if you’re like me, you learned what the three (or four, depending on who you talk to; but if I added the forth, I couldn’t run with this whole pie joke…) pillars of OOP are: polymorphism, inheritance, and encapsulation.
Let’s go over ‘em one-by-one.
Note! Some people may argue that the principles of SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion) are the true pillars of OOP & OOD (Object-Oriented Design). I’m not here to argue for or against, but PIE is a typical textbook explanation of OOP that most people are familiar with. Perhaps I’ll do a post on the SOLID principles in the future.
Polymorphism
You’ve probably been bashed over the head enough times (assuming your a CS student or software dev) to know that polymorphism is greek for “many forms.” What does this mean exactly? Well, it means in OOP languages that a single type or class can take many forms. Referring to the image on the right, imagine we have a base class named Animal
. From Animal
we can derive several classes (called… derived classes): Dog
, Cat
, and Duck
. These derived classes inherit (another piece of the “pie”… ha) any shared abilities from Animal
(such as speak()
), such that a Dog
is-a Animal
. You could modify the speak()
function of Dog
, Cat
, and Duck
so that they make their respective sounds (“Meow,” etc).
Now, say you had an vector of Animal
pointers and you decided to add a pointer to a Duck
object, a Dog
object, and a Cat
object (you can do this because all three of type Animal
). If you were to iterate through the vector and make a call to each object’s speak()
function, you’d get what you’d expect: “Quack,” “Woof,” “Meow.” It doesn’t matter if it’s a Dog
or a Duck
, it’s guaranteed that if the object is of type Animal
it has a speak()
function that is callable. That’s the power of polymorphism.
Here’s a code example:
#include <iostream>
#include <vector>
class Animal
{
public:
Animal(){}
~Animal(){}
virtual void speak() { std::cout << "Noise"; };
};
class Dog : public Animal
{
public:
Dog(){}
~Dog(){}
void speak() { std::cout << "Woof!"; }
};
int main() {
std::vector<Animal*> v { new Animal(), new Dog() };
for (const auto a : v)
{
a->speak();
std::cout << endl;
}
}
Note! If you did not use a vector of Animal
pointers but used a vector of Animal
objects (std::vector<Animal>
), you’d experience a problem in the range-based for loop - when a
is Dog
, a
will print “Noise,” like it’s parent class. Why? When you add the Dog
object to the vector (of Animal
objects), it will only copy the Animal
part of Dog
, leaving all the unique Dog
bits behind.
Next, inheritance!