0% found this document useful (0 votes)
11 views5 pages

Bcp121 Week 10 Lecture 1

This lecture covers polymorphism in C++, focusing on virtual functions, abstract classes, and dynamic binding. It explains the difference between static and dynamic polymorphism, the importance of virtual destructors, and how abstract base classes define interfaces for derived classes. By the end, students will understand how to implement these concepts in their programming.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views5 pages

Bcp121 Week 10 Lecture 1

This lecture covers polymorphism in C++, focusing on virtual functions, abstract classes, and dynamic binding. It explains the difference between static and dynamic polymorphism, the importance of virtual destructors, and how abstract base classes define interfaces for derived classes. By the end, students will understand how to implement these concepts in their programming.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

Okay, here is the lecture text structured as a document:

Week 10 Lecture: Polymorphism in C++ – Virtual


Functions and Abstract Classes
Course: Computer Programming in Technology 2 (CPT 102 - C++) Topic: Polymorphism:
Overriding Base Class Functions, Virtual Functions, Abstract Base Classes, and Dynamic
Binding Date: April 1, 2025 Location: Surigao City Duration: Approximately 1.5–2 hours
Hello, everyone! Welcome to Week 10 of CPT 102. Today, we’re tackling polymorphism—one
of the coolest and most powerful concepts in object-oriented programming. By the end of this
lecture, you’ll understand how to make objects behave differently based on their actual type,
even when accessed through a base class pointer. We’ll cover virtual functions, dynamic
binding, virtual destructors, and abstract base classes. Ready? Let’s dive in!

Part 1: Introducing Polymorphism (20 minutes)


Let’s start with the big picture. Polymorphism means “many forms” in Greek, and in C++, it’s
the ability of an object to take on different behaviors depending on its type. There are two kinds:
●​ Static Polymorphism: Happens at compile time—like function overloading or operator
overloading. You’ve seen this already.
●​ Dynamic Polymorphism: Happens at runtime, using inheritance and pointers. That’s our
focus today.
Imagine this: You have a Shape base class and derived classes like Circle and Rectangle. You
create a pointer Shape* shapePtr and point it to a Circle object. When you call
shapePtr->draw(), you want it to draw a circle—not some generic shape. That’s what
polymorphism lets us do, and it’s all about runtime behavior. Questions so far? Let’s see why
this doesn’t work by default.

Part 2: The Problem – Static Binding with Pointers (20 minutes)


Here’s where things get tricky. Let’s look at an example. Suppose we have:
#include <iostream>​
using namespace std;​

class Base {​
public:​
void print() { cout << "Base print\n"; }​
};​

class Derived : public Base {​
public:​
void print() { cout << "Derived print\n"; }​
};​

Now, if I do:
Derived d;​
d.print(); // Outputs: "Derived print"​
That’s fine—it calls the Derived version. But watch this:
Base* ptr = new Derived();​
ptr->print(); // Outputs: "Base print"​
delete ptr; // Remember to delete allocated memory​

What?! Why didn’t it call Derived::print()? This is static binding. The compiler looks at the
pointer type (Base*) and decides at compile time to call Base::print(), ignoring the actual object
type (Derived). This isn’t what we want for polymorphism. How do we fix it? Let’s find out.

Part 3: The Solution – Virtual Functions & Dynamic Binding (30


minutes)
Enter virtual functions. Add one word to the base class:
#include <iostream>​
using namespace std;​

class Base {​
public:​
virtual void print() { cout << "Base print\n"; } // Added virtual
keyword​
virtual ~Base() {} // Added virtual destructor (good practice)​
};​

class Derived : public Base {​
public:​
void print() override { cout << "Derived print\n"; } // Added
override specifier​
};​

Now:
Base* ptr = new Derived();​
ptr->print(); // Outputs: "Derived print"​
delete ptr;​

Magic! This is dynamic binding—the decision about which print() to call happens at runtime,
based on the object’s actual type. How does this work? Behind the scenes, C++ uses a v-table
(virtual table)—a lookup table created for each class with virtual functions. When you call a
virtual function through a pointer, the program checks the v-table to find the right function. Don’t
worry about the details—just know virtual enables this runtime flexibility.
Let’s make it safer with a C++11 feature: the override specifier. Rewrite Derived like this:
class Derived : public Base {​
public:​
void print() override { cout << "Derived print\n"; }​
};​

override ensures you’re actually overriding a virtual function. If you typo the function name or
signature, the compiler will catch it. Pretty handy, right? Any questions about virtual functions or
dynamic binding?

Part 4: Virtual Destructors (15 minutes)


Now, a critical detail: destructors. Imagine you write:
Base* ptr = new Derived();​
delete ptr;​

If Base doesn’t have a virtual destructor, only Base::~Base() runs, and Derived::~Derived() is
skipped. This can cause memory leaks or undefined behavior if Derived allocates resources. Fix
it like this:
#include <iostream>​
using namespace std;​

class Base {​
public:​
virtual void print() { cout << "Base print\n"; }​
// Make the destructor virtual!​
virtual ~Base() { cout << "Base destroyed\n"; }​
};​

class Derived : public Base {​
public:​
void print() override { cout << "Derived print\n"; }​
// Derived destructor is automatically virtual if base is​
~Derived() override { cout << "Derived destroyed\n"; }​
};​

// Example usage:​
// Base* ptr = new Derived();​
// delete ptr; // Now calls Derived destructor then Base destructor​

Now, delete ptr calls both destructors in the right order: Derived first, then Base. Rule of thumb:
If a class has any virtual functions, give it a virtual destructor. Got it? Let’s move to something
even more abstract.

Part 5: Abstract Base Classes & Pure Virtual Functions (30 minutes)
Sometimes, a base class isn’t meant to be instantiated—it’s just an interface. Enter Abstract
Base Classes (ABCs) and pure virtual functions. Here’s how:
#include <iostream>​
using namespace std;​

// Abstract Base Class (ABC)​
class Shape {​
public:​
// Pure virtual function (makes Shape abstract)​
virtual double area() const = 0;​

// Virtual destructor is still needed for proper cleanup via base
pointer​
virtual ~Shape() { cout << "Shape destroyed\n"; }​
};​

The = 0 makes area() pure virtual, meaning Shape can’t be instantiated:


// Shape s; // Error: Cannot declare variable 's' to be of abstract
type 'Shape'​

Derived classes must implement all pure virtual functions to become concrete:
#include <cmath> // For M_PI if available, otherwise use 3.14159​

class Circle : public Shape {​
private:​
double radius;​
public:​
Circle(double r) : radius(r) { cout << "Circle created\n"; }​
~Circle() override { cout << "Circle destroyed\n"; }​

// Provide implementation for the pure virtual function​
double area() const override {​
return 3.14159 * radius * radius; // Or use M_PI​
}​
};​

Now Circle is usable:


Shape* ptr = new Circle(5);​
cout << "Area: " << ptr->area() << endl; // Outputs: Area: 78.53975​
delete ptr; // Calls ~Circle() then ~Shape()​

ABCs define a contract—any derived class must provide an area() implementation (or remain
abstract itself). This is perfect for things like shapes, animals, or game objects where the base is
just a blueprint. Questions about ABCs or pure virtual functions?

Part 6: Summary (5 minutes)


Let’s recap:
●​ Virtual functions enable runtime polymorphism through base pointers, using dynamic
binding via the v-table.
●​ The override specifier helps ensure you are correctly overriding a base class virtual
function.
●​ Virtual destructors ensure proper cleanup when deleting derived objects via base
pointers. Add virtual ~Base() {} if your class might be used as a base class.
●​ Abstract Base Classes (ABCs) with pure virtual functions (= 0) define interfaces that
derived classes must implement. ABCs cannot be instantiated.
This is polymorphism in action—flexible, powerful, and essential for real-world C++
programming. In the lab, you’ll code this yourself with weapons and shapes. Any final questions
before we wrap up?

Closing
That’s it for today’s lecture! You’re now equipped to handle polymorphism like pros. Bring your
energy to the lab—we’ll write code to see virtual functions and ABCs in action. See you there!

You might also like