📖
Go C++
  • Introduction
  • Chapter 1: What You Must Know First
    • Virtual Address Space of Process: Memory Partition and Layout
    • Function Call: Stack Frame
    • Program Compiling and Linking
  • Chapter 2: C++ Basics Improvement
    • Default Parameters
    • Inline Function
    • Function Overloading
    • new and delete
    • const and Pointers
    • References in Detail
  • Chapter 3: Object-Oriented Principles
  • Class and Object
  • Constructor and Destructor
  • Shallow Copy and Deep Copy
  • Initializer List
  • Various Member Functions
  • Pointer to Class Members
  • Chapter 4: Template Programming
  • Function Templates
  • Class Templates
  • Memory Allocators
  • Chapter 5: Operator Overloading
    • Operator Overloading
    • Introduction to Iterators
    • Issues of Iterator Invalidation
    • More about new and delete
    • Overloading of new and delete: Object Pool
  • Chapter 6: Inheritance and Polymorphism
    • Look inside Inheritance
    • More about Inheritance
    • Virtual Functions, Static Binding and Dynamic Binding
    • More about Virtual Functions
    • Understanding Polymorphism
    • Abstract Classes
    • Frequently Asked Interview Questions: Polymorphism
  • Chapter 7: Multiple Inheritance
    • Virtual Inheritance and Virtual Base Classes
    • Diamond Problem
    • Four Kinds of Type Conversions
  • Chapter 8: Standard Template Library
    • Sequence Containers
    • Container Adaptors
    • Associative Containers
    • More about Iterators
    • Function Objects
    • Generic Algorithms, Binders and Lambda Expressions
  • Chapter 9: Object Optimization
    • Behind the Object
    • Optimizing Objects in Functions
    • Member Functions with Rvalue References
    • Move Semantics and Perfect Forwarding
  • Chapter 10: Smart Pointers
    • Smart Pointers
    • Smart Pointers without Reference Counting
    • Smart Pointers with Reference Counting
    • Custom Deleters
  • Chapter 11: Function Objects and Binders
    • More about Binders
    • Introduction to std::function
    • Template Specialization and Argument Deduction
    • More about std::function
    • std::bind(): A Simple Thread Pool
    • More about Lambda Expressions
  • Chapter 12: Multithreading
    • Important Features in C++11
    • Multithreaded Programming with std::thread
    • Mutual Exclusion
    • Producer-Consumer Problem
    • Atomic Operations
    • Thread Visibility and volatile
  • Chapter 13: Design Patterns
    • Singleton Pattern
    • Factory Pattern
    • Proxy Pattern
    • Decorator Pattern
    • Adapter Pattern
    • Observer Pattern
Powered by GitBook
On this page

Was this helpful?

  1. Chapter 6: Inheritance and Polymorphism

Abstract Classes

Let's take another look at what we wrote earlier:

class Animal {
public:
    Animal(string name) : _name(name) {}
    virtual void bark() {}
protected:
    string _name;
};
​
class Cat : public Animal {
public:
    Cat(string name) : Animal(name) {}
    void bark() {
        cout << _name << "Meow!" << endl;
    }
};
​
class Dog : public Animal {
public:
    Dog(string name) : Animal(name) {}
    void bark() {
        cout << _name << "Woof!" << endl;
    }
};
​
class Bear : public Animal {
public:
    Bear(string name) : Animal(name) {}
    void bark() {
        cout << _name << "Rua!" << endl;
    }
};

Remember that the original intention of defining class Animal is not to make Animal an abstract of some entities, but to:

  1. Let all derived classes inherit the member variables of Animal to reuse its properties.

  2. Keep a unified interface for all derived classes to override it to achieve polymorphism.

Hence, we can defined Animal as an abstract class:

class Animal {
public:
    Animal(string name) : _name(name) {}
    virtual void bark() = 0;
protected:
    string _name;
};

Here we declared a virtual function bark(), but assign its address to 0. In this case, bark() is a pure virtual function. A class with pure virtual functions is called an abstract class. An abstract class can not be instantiated, but can have pointers and references:

int main() {
    Animal a;   // No
    Animal *pa; // Yes
    return 0;
}

Let's look at another example. Here we defined an abstract class Car, and has a method which returns remaining miles under the current fuel level.

class Car {
public:
    Car(string name, double oil) : _name(name), _oil(oil) {}
    double getLeftMiles(double oil) {
        return oil * getMilesPerGallon();
    }
protected:
    string _name;
    double _oil;
    virtual double getMilesPerGallon() = 0;
};

Then we defined three cars of different brands, with different mileages per gallon.

class Benz : public Car {
public:
    Benz(string name, double oil) : Car(name, oil) {}
    double getMilesPerGallon() {return 20.0;}
};
​
class Audi : public Car {
public:
    Audi(string name, double oil) : Car(name, oil) {}
    double getMilesPerGallon() {return 18.0;}
};
​
class BMW : public Car {
public:
    BMW(string name, double oil) : Car(name, oil) {}
    double getMilesPerGallon() {return 19.0;}
};

Moreover, we provide an interface to get the remaining miles of the car, and passes in different objects:

double showCarLeftMiles(Car &car) {
    cout << car.getName() << " " << car.getLeftMiles() << endl;
}
​
int main() {
    Benz a("Benz", 20.0);
    Audi b("Audi", 20.0);
    BMW c("BWM", 20.0);
    showCarLeftMiles(a);    // Benz 400
    showCarLeftMiles(b);    // Audi 360
    showCarLeftMiles(c);    // BMW 380
    return 0;
}

Now in showCarLeftMiles(), the parameter is a Car object instead of a pointer, isn't it a static binding? How can we achieve polymorphism? Of course it is a static binding here, but notice that in Car::getLeftMiles(), the virtual function getMilesPerGallon() is called with this->getMilesPerGallon(). Since *this is a Car pointer, it is still a dynamic binding, so the corresponding method of different objects is called.

PreviousUnderstanding PolymorphismNextFrequently Asked Interview Questions: Polymorphism

Last updated 4 years ago

Was this helpful?