Core Characteristics of Object-Oriented Programming (OOP) in C++: Understanding, Implementation, and Examples of Polymorphism

Follow me to achieve: cognitive evolution, capability evolution, and wealth evolution!This article focuses on C++ technology, part of the professional capability evolution series.Introduction:Do you know the concept of ‘Polymorphism’, one of the three main characteristics of C++?What are its functions and benefits?Part 1:Concept of PolymorphismPolymorphism is the third core characteristic of object-oriented programming, allowing objects of different classes to respond differently to the same message, i.e., “one interface, multiple implementations”.

Polymorphism (多态) originates from Greek, meaning “many forms”. In OOP, polymorphism mainly has two forms:

  1. Compile-time Polymorphism (Static Polymorphism):

    Achieved through function overloading and operator overloading

    Determines which function to call at compile time

  2. Run-time Polymorphism (Dynamic Polymorphism):

    Achieved through inheritance and virtual functions

    Determines which function to call at run time

The main advantages of polymorphism are:

  1. Improves code scalability and maintainability

  2. Makes interfaces more general, reducing conditional checks

  3. Supports the “Open/Closed Principle” (open for extension, closed for modification)

Part 2:Implementation of Polymorphism

1. Implementation of Compile-time Polymorphism

(1) Function Overloading

class Printer {public:    void print(int i) {        cout << "Printing integer: " << i << endl;    }    void print(double f) {        cout << "Printing float: " << f << endl;    }    void print(string s) {        cout << "Printing string: " << s << endl;    }};

(2) Operator Overloading

class Complex {private:    double real, imag;public:    Complex(double r = 0, double i = 0) : real(r), imag(i) {}    Complex operator + (Complex const &obj) {        return Complex(real + obj.real, imag + obj.imag);    }    void display() {        cout << real << " + " << imag << "i" << endl;    }};

2. Implementation of Run-time Polymorphism

Run-time polymorphism is achieved through virtual functions, key points:

  • Declare virtual functions in the base class (using the <span>virtual</span> keyword)

  • Override virtual functions in derived classes

  • Call virtual functions through base class pointers or references

class Base {public:    virtual void show() {  // Virtual function        cout << "Base class show()" << endl;    }};class Derived : public Base {public:    void show() override {  // Override virtual function        cout << "Derived class show()" << endl;    }};

Part 3:Examples of Polymorphism

Example 1: Run-time Polymorphism (Virtual Functions)

#include <iostream>using namespace std;// Base class: Shapeclass Shape {protected:    string name;public:    Shape(string n) : name(n) {}    // Virtual function: calculate area    virtual double area() const {        cout << "Calculating area of base class Shape" << endl;        return 0;    }    // Virtual destructor (important!)    virtual ~Shape() {        cout << "Shape destructor" << endl;    }};// Derived class: Circleclass Circle : public Shape {private:    double radius;public:    Circle(string n, double r) : Shape(n), radius(r) {}    // Override area function    double area() const override {        cout << name << "'s area: ";        return 3.14159 * radius * radius;    }    ~Circle() override {        cout << "Circle destructor" << endl;    }};// Derived class: Rectangleclass Rectangle : public Shape {private:    double width, height;public:    Rectangle(string n, double w, double h)         : Shape(n), width(w), height(h) {}    // Override area function    double area() const override {        cout << name << "'s area: ";        return width * height;    }    ~Rectangle() override {        cout << "Rectangle destructor" << endl;    }};int main() {    // Array of base class pointers pointing to different derived class objects    Shape* shapes[3];    shapes[0] = new Circle("Circle 1", 5.0);    shapes[1] = new Rectangle("Rectangle 1", 4.0, 6.0);    shapes[2] = new Circle("Circle 2", 3.0);    // Polymorphic call: call the corresponding area() based on actual object type    for (int i = 0; i < 3; ++i) {        cout << shapes[i]->area() << endl;    }    // Free memory    for (int i = 0; i < 3; ++i) {        delete shapes[i];  // Polymorphic call to destructor    }    return 0;}

Compilation Process

g++ -std=c++11 oop.cpp -o oop

Run Result

Circle 1's area: 78.5397Rectangle 1's area: 24Circle 2's area: 28.2743Circle destructorShape destructorRectangle destructorShape destructorCircle destructorShape destructor

Example 2: More Complex Polymorphic Application

#include <iostream>#include <vector>using namespace std;// Abstract base class: Employeeclass Employee {protected:    string name;    double salary;public:    Employee(string n, double s) : name(n), salary(s) {}        // Pure virtual function, making Employee an abstract class    virtual void work() = 0;        // Virtual function: calculate bonus    virtual double calculateBonus() const {        return salary * 0.1;  // Default bonus is 10% of salary    }    string getName(){return name;}        virtual ~Employee() {}};// Derived class: Developerclass Developer : public Employee {private:    string programmingLanguage;public:    Developer(string n, double s, string lang)        : Employee(n, s), programmingLanguage(lang) {}        void work() override {        cout << name << " is coding in " << programmingLanguage              << "..." << endl;    }        double calculateBonus() const override {        return salary * 0.15;  // Developer bonus is 15%    }};// Derived class: Managerclass Manager : public Employee {private:    int teamSize;public:    Manager(string n, double s, int size)        : Employee(n, s), teamSize(size) {}        void work() override {        cout << name << " is managing a team of " << teamSize              << " people..." << endl;    }        double calculateBonus() const override {        return salary * 0.2 + teamSize * 500;  // Manager bonus is higher    }};int main() {    vector<Employee*> employees;        employees.push_back(new Developer("Zhang San", 15000, "C++"));    employees.push_back(new Manager("Li Si", 25000, 8));    employees.push_back(new Developer("Wang Wu", 18000, "Python"));        // Polymorphic call    for (Employee* emp : employees) {        emp->work();        cout << emp->getName() << "'s bonus: "              << emp->calculateBonus() << endl;        cout << "-------------------" << endl;    }        // Free memory    for (Employee* emp : employees) {        delete emp;    }        return 0;}

Compilation Process

g++ -std=c++11 polymorphism.cpp -o polymorphism

Run Result

Zhang San is coding in C++...Zhang San's bonus: 2250-------------------Li Si is managing a team of 8 people...Li Si's bonus: 9000-------------------Wang Wu is coding in Python...Wang Wu's bonus: 2700-------------------

Part 4:Advanced Topics in Polymorphism

1. Pure Virtual Functions and Abstract Classes

  • Pure virtual function:<span>virtual return_type function_name(parameters) = 0;</span>

  • A class containing pure virtual functions is an abstract class and cannot be instantiated

  • Derived classes must implement all pure virtual functions to be instantiated

2. The override and final Keywords (C++11)

  • <span>override</span>: Explicitly indicates overriding a virtual function, helping the compiler check

  • <span>final</span>: Prevents derived classes from overriding a virtual function or prevents a class from being inherited

3. Virtual Destructors

  • The base class destructor should be a virtual function to ensure that the derived class destructor is correctly called when deleting derived class objects through base class pointers

4. Virtual Function Table (vtable)

  • The compiler creates a virtual function table for each class containing virtual functions

  • Objects contain a pointer to the vtable (vptr)

  • At run time, the correct function is looked up and called through the vptr

The above content will be detailed in subsequent discussions.

Part 5: Summary of the Advantages of Polymorphism

  1. Unified Interface: Operate various derived class objects through the base class interface

  2. Strong Scalability: Adding new classes does not affect existing code

  3. Concise Code: Reduces conditional statements

  4. High Flexibility: Determines which function to call at run time

Polymorphism is one of the most powerful features of object-oriented design, and its proper use can significantly improve code quality and maintainability.

Did you understand? Next time we will talk about the basics: encapsulation and inheritance!

Leave a Comment