BTP200

Introduction: Part II

Derived Classes and Functions in a Hierarchy

Summary

Introduction to the second half of BTP200

Inheritance and Hierarchy

Derived Classes

Functions in a Hierarchy

Introduction

About Myself

Electrical Engineer by trade

+20 years of experience in Software Development

Teaching this course for the sixth time!

Brazilian, Canadian, and French

Father of two little honey badgers tasmanian devils beautiful children

What we will Learn

  Derived Classes

  Virtual Functions

  Function Templates

  Polymorphism

  Language Standards

Delivery Method

Lectures will be in person

The addendum has been slightly changed

Workshops will also be in person - submission online is possible, but not recommended

Blackboard will be used for assignments, for announcements, and for grading purposes

Course's website contains general info and slides

Evaluation

Five Workshops (1%): In person labs

Five Quizzes (1.5%): Blackboard Tests

One Project (20% or 10%): In person presentation

One Final Exam (30% or 40%): in class pen-on-paper test

Inheritance and Hierarchy

Inheritance

In OOP, the use of inheritance allows for code reusability

One class can inherit elements from another class and add its own extra elements

For example:

  quadrilateral parallelogram rectangle square

Hierarchy

Inheritance is naturally hierarchical

It ranks (orders) entities in an ordered structure

You can think of it as: (more general) (more specific)

A class lower in the hierarchy is a kind of class higher in the hierarchy

For example:

  chordata mammal primate homo sapiens

Derived Classes

Derived Classes

If a class B inherits from a class A, it is said to be a derived class of A

In this case, A is said to be the base class for B

Note that a derived class can be the base class for another class

Visual Representation

Derived Classes

A derived class contains all variables (properties) and normal member functions of its base class

A derived class can add its own variables (properties) and normal member functions of its base class

A derived class does not inherit:

  Constructors and destructors

  Assignment operator

Derived Classes

Example

#include <iostream>

class Shape
{
protected:
    float width_;
    float height_;

public:
    void set_width(int w)
    {
        width_ = w;
    }
    void set_height(int h)
    {
        height_ = h;
    }
};

// Derived class
class Rectangle : public Shape
{
public:
    int get_area()
    {
        return (width_ * height_);
    }
};

// Derived class
class Triangle : public Shape
{
public:
    int get_area()
    {
        return (width_ * height_ * 0.5);
    }
};

int main(void)
{
    Rectangle Rec;
    Triangle Tri;

    Rec.set_width(3);
    Rec.set_height(4);

    std::cout << "Area: " << Rec.get_area() << std::endl;

    Tri.set_width(3);
    Tri.set_height(4);

    std::cout << "Area: " << Tri.get_area() << std::endl;

    return 0;
}
              

Access Specifiers

C++ provides three levels of access for class member variables and functions:

  private Acessible only within the class

  protected Accessible within the class or within
derived classes

  public Accessible anywhere

Design Considerations

Granting protected access to a member variable exposes it

Hence, it is normally considered poor design

Consider providing getters and setters instead

There are exceptions, though:

The same team is working on both classes

The base class is provided as a template

Functions in a Hierarchy

Constructors and Destructors

A derived class does not inherits constructors and destructors from the base class

They have their own constructors and destructors

The constructors from a derived class calls the constructors of the base class before it starts

The destructor from a derived class calls the destructors of the base class after it ends

Constructors and Destructors

Example

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base class object was created!"
                  << std::endl;
    }
    ~Base()
    {
        std::cout << "Base class object was destroyed!"
                  << std::endl;
    }
};

class Derived : public Base
{
public:
    Derived()
    {
        std::cout << "Derived class object was created!"
                  << std::endl;
    }
    ~Derived()
    {
        std::cout << "Derived class object was destroyed! "
                  << std::endl;
    }
};

int main(void)
{
    Base baseObject;
    Derived derivedObject;

    return 0;
}
              

Constructors and Destructors

A derived class constructor can pass arguments to the base class constructor

The syntax is:

derivedClass(Type argumentName) : baseClass(argumentName)

Constructors and Destructors

Example with Arguments

#include <iostream>
#include <cstring>
const int N = 15;

class Base
{
protected:
    char name_[N];

public:
    Base()
    {
        name_[0] = '\0';
        std::cout << "Base class object was created!"
                  << std::endl;
    }
    Base(const char *argument)
    {
        strncpy(name_, argument, N);
        name_[N - 1] = '\0';
        std::cout << "Base class object was created for "
                  << name_ << std::endl;
    }
    ~Base()
    {
        std::cout << "Base class object was destroyed! "
                  << "Bye " << name_ << std::endl;
    }
};

class Derived : public Base
{
    int age_;
public:
    Derived()
    {
        std::cout << "Derived class object was created!"
                  << std::endl;
    }
    Derived(const char *argument, int age) : Base(argument)
    {
        age_ = age;
        std::cout << "Derived class object was created for "
                  << name_ << std::endl;
    }
    ~Derived()
    {
        std::cout << "Derived class object was destroyed! "
                  << "Bye " << name_ << std::endl;
    }
};

int main(void)
{
    Base baseObject("Base Bill");
    Derived derivedObject("Derived Bob", 25);

    return 0;
}
              

Shadowing

A derived class can have member variables or functions with the same name as the ones in the base class

When this happens, the compiler binds a call the member function or variable from the derived class

We say that the member variable (or function) of the derived class shadows the one from the base class

Shadowing

Example

#include <iostream>
#include <cstring>
const int N = 15;

class Person
{
protected:
    char name_[N];

public:
    Person()
    {
        name_[N - 1] = '\0';
    }
    Person(const char *argument)
    {
        strncpy(name_, argument, N);
        name_[N - 1] = '\0';
    }
    void display() const
    {
        std::cout << name_ << "." << std::endl;
    }
};

class Student : public Person
{
public:
    Student(const char *argument) : Person(argument)
    {
    }
    void display() const
    {
        std::cout << "Hi, I am a Student called ";
        Person::display();
    }
};

class Faculty : public Person
{
public:
    Faculty(const char *argument) : Person(argument)
    {
    }
    void display() const
    {
        std::cout << "Hi, I am a Faculty called ";
        Person::display();
    }
};

int main(void)
{
    Student student("John Doe");
    Faculty faculty("Jane Smith");

    student.display();
    faculty.display();

    return 0;
}
              

Shadowing

It possible to access the base version of a shadowed identifier

For this, you have to use scope resolution

The syntax is:

baseClass::shadowedIdentifier(arguments)

Shadowing

Example with scope resolution

#include <iostream>
#include <cstring>
const int N = 15;

class Person
{
protected:
    char name_[N];

public:
    Person()
    {
        name_[0] = '\0';
    }
    Person(const char *argument)
    {
        strncpy(name_, argument, N);
        name_[N - 1] = '\0';
    }
    void display() const
    {
        std::cout << "Hi, I am a Person called "
                  << name_ << "." << std::endl;
    }
};

class Student : public Person
{
public:
    Student(const char *argument) : Person(argument)
    {
    }
    void display() const
    {
        std::cout << "Hi, I am a Student called "
                  << name_ << "." << std::endl;
    }
    void display_from_base() const
    {
        Person::display();
    }
};

class Faculty : public Person
{
public:
    Faculty(const char *argument) : Person(argument)
    {
    }
    void display() const
    {
        std::cout << "Hi, I am a Faculty called "
                  << name_ << "." << std::endl;
    }
};

int main(void)
{
    Person person("Base Bill");
    Student student("John Doe");
    Faculty faculty("Jane Smith");

    person.display();
    student.display();
    student.display_from_base();
    faculty.display();

    return 0;
}
              

Suggested Reading

Derived Classes

Functions in a Hierarchy

Access Specifiers