Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding C++ Polymorphism: Implementation and Principles

Tech 1

Virtual Functions

A function becomes virtual when prefixed with virtual.

class BaseClass {
public:
    virtual void operation() {}; // This is a virtual function
};

Inheritance of Virtual Functions

Virtual function inheritance embodies interface inheritance, where the function signature (including return type, name, parameter list, and default parameters) is inherited, allowing overriding of the implementation.

Virtual Classes / Virtual Base Classes

A class containing virtual functions is a virtual class; if it serves as a base class, it is termed a virtual base class.

Overriding / Overwriting

Conditions: The function name, parameters (types only, not default parameters), and return type must match. Overriding replaces the function body of an inherited virtual function, reflecting interface inheritance. Only virtual functions can be overridden; non-virtual functions result in hiding or redefinition.

Conditions for Polymorphism

Two conditions must be met for polymorphism:

  1. Overriding of a virtual function.
  2. Calling the virtual function via a pointer or reference of the base class type.
class Person {
public:
    virtual void purchaseTicket() {
        std::cout << "Full fare" << std::endl;
    }
};

class Student : public Person {
public:
    virtual void purchaseTicket() override {
        std::cout << "Half fare" << std::endl;
    }
};

void processPurchase(Person& p) {
    p.purchaseTicket();
}

int main() {
    Person adult;
    Student pupil;
    processPurchase(adult); // Outputs: Full fare
    processPurchase(pupil);  // Outputs: Half fare
    return 0;
}

Polymorphism example

Additional Polymorphic Behaviors

  • Derived classes can omit virtual for overridden functions; if the base function is virtual, subsequent inherited versions remain virtual.
  • Covariance allows return types to differ in pointer or reference form, maintaining type safety.

Inheritance and Destructors

In inheritance hierarchies, destructors should be virtual to ensure proper cleanup when using base class pointers.

class Base {
public:
    virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};

class Derived : public Base {
public:
    virtual ~Derived() override { std::cout << "Derived destructor" << std::endl; }
};

int main() {
    Base* ptr = new Derived();
    delete ptr; // Properly calls both destructors
    return 0;
}

Destructor example

C++11 Keywords: override and final

  • final: Prevents further inheritance or overriding.
    class FinalClass final {}; // Cannot be inherited
    class Base {
    public:
        virtual void method() final {}; // Cannot be overridden
    };
    
  • override: Ensures a function overrides a base class virtual function, generating a compile-time error if not.
    class Base {
    public:
        virtual void action() {}
    };
    class Derived : public Base {
    public:
        void action() override {} // Compiles only if it overrides
    };
    

Pure Virtual Functions and Abstract Classes

A pure virtual function is declared with = 0 and defines an abstract class, which cannot be instantiated.

class AbstractClass {
public:
    virtual void perform() = 0; // Pure virtual function
};

Mechanism of Polymorphism

Polymorphism is implemented through virtual function tibles (vtables). Each object with virtual functions contains a vtable pointer (_vptr) pointing to an array of function addresses.

  • Vtables are generated at compile-time.
  • Derived classes inherit and may modify vtables by overriding functions.

Example: Vtable Illustration

class BaseType {
public:
    virtual void funcA() {}
    virtual void funcB() {}
};

class DerivedType : public BaseType {
public:
    void funcA() override {}
    virtual void funcC() {}
};

Vtable example

Multiple Inheritance and Vtables

In multiple inheritance, derived classes have multiple vtables, one per base class. Additional virtual functions are appended to the first base class's vtable.

class BaseOne {
public:
    virtual void op1() {}
};
class BaseTwo {
public:
    virtual void op2() {}
};
class MultiDerived : public BaseOne, public BaseTwo {
public:
    void op1() override {}
    virtual void op3() {}
};

Static vs. Dynamic Binding

  • Static binding: Resolved at compile-time (e.g., function overloading).
  • Dynamic binding: Resolved at runtime via vtables (polymorphism).

Performance Considerations

Virtual function calls via pointers or references are generally slower than direct calls due to vtable lookup, but non-polymorphic calls may optimize similarly.

Key Concepts

  • Inline and virtual: Can coexist but inline may be ignored in polymorphic contexts.
  • Static functions cannot be virtual as they lack this pointer.
  • Constructors and copy constructors cannot be virtual.

This article covers the fundamentals and internal workings of C++ polymorphism, essential for advanced object-oriented programming.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.