0% found this document useful (0 votes)
176 views11 pages

Upcast&Downcast

This document discusses upcasting and downcasting in C++. Upcasting involves treating a derived class pointer as a base class pointer, allowing for polymorphic functions to work on derived classes. Downcasting goes the opposite direction but is unsafe without a dynamic cast, as the object may not actually be of the derived type. The key points are: - Upcasting occurs implicitly and allows accessing only base class members, while downcasting requires an explicit cast. - Downcasting can cause errors if the object is not actually of the derived type being cast to. - Dynamic cast provides a safe way to downcast by returning nullptr instead of causing errors if the cast fails.

Uploaded by

CR3
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)
176 views11 pages

Upcast&Downcast

This document discusses upcasting and downcasting in C++. Upcasting involves treating a derived class pointer as a base class pointer, allowing for polymorphic functions to work on derived classes. Downcasting goes the opposite direction but is unsafe without a dynamic cast, as the object may not actually be of the derived type. The key points are: - Upcasting occurs implicitly and allows accessing only base class members, while downcasting requires an explicit cast. - Downcasting can cause errors if the object is not actually of the derived type being cast to. - Dynamic cast provides a safe way to downcast by returning nullptr instead of causing errors if the cast fails.

Uploaded by

CR3
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/ 11

Introduction

Upcasting and downcasting are an important part of C++. Upcasting and


downcasting gives a possibility to build complicated programs with a simple
syntax. It can be achieved by using Polymorphism.

C++ allows that a derived class pointer (or reference) to be treated as base
class pointer. This is upcasting.

Downcasting is an opposite process, which consists in converting base class


pointer (or reference) to derived class pointer.

Upcasting and downcasting should not be understood as a simple casting of


different data types. It can lead to a great confusion.

In this topic, we will use the following hierarchy of classes:

As you can see, Manager and Clerk are both Employee. They are both Person
too. What does it mean? It means that Manager and Clerk classes inherit
properties of Employee class, which inherits properties of Person class.

For example, we don’t need to specify that both Manager and Clerk are
identified by First and Last name, have salary; you can show information
about them and add a bonus to their salaries. We have to specify these
properties only once in the Employee class:
In the same time, Manager and Clerk classes are different. Manager takes a
commission fee for every contract, and Clerk has information about his
Manager:

Try It

#include <iostream>

using namespace std;

class Person

//content of Person

};

class Employee:public Person

public:

Employee(string fName, string lName, double sal)

FirstName = fName;

LastName = lName;

salary = sal;

string FirstName;

string LastName;
double salary;

void show()

cout << "First Name: " << FirstName << " Last Name:
" << LastName << " Salary: " << salary<< endl;

void addBonus(double bonus)

salary += bonus;

};

class Manager :public Employee

public:

Manager(string fName, string lName, double sal, double


comm) :Employee(fName, lName, sal)

Commision = comm;

double Commision;

double getComm()

return Commision;
}

};

class Clerk :public Employee

public:

Clerk(string fName, string lName, double sal, Manager* man)


:Employee(fName, lName, sal)

manager = man;

Manager* manager;

Manager* getManager()

return manager;

};

void congratulate(Employee* emp)

cout << "Happy Birthday!!!" << endl;

emp->addBonus(200);

emp->show();
};

int main()

//pointer to base class object

Employee* emp;

//object of derived class

Manager m1("Steve", "Kent", 3000, 0.2);

Clerk c1("Kevin","Jones", 1000, &m1);

//implicit upcasting

emp = &m1;

//It's ok

cout<<emp->FirstName<<endl;

cout<<emp->salary<<endl;

//Fails because upcasting is used

//cout<<emp->getComm();

congratulate(&c1);

congratulate(&m1);
cout<<"Manager of "<<c1.FirstName<<" is "<<c1.getManager()-
>FirstName;

Manager and Clerk are always Employees. Moreover, Employee is a Person.


Therefore, Manager and Clerk are Persons too. You have to understand it
before we start learning upcasting and downcasting.

Both upcasting and downcasting do not change object by itself. When you use
upcasting or downcasting you just “label” an object in different ways.

UPCASTING
Upcasting is a process of treating a pointer or a reference of derived class
object as a base class pointer. You do not need to upcast manually. You just
need to assign derived class pointer (or reference) to base class pointer:

//pointer to base class object

Employee* emp;

//object of derived class

Manager m1("Steve", "Kent", 3000, 0.2);

//implicit upcasting

emp = &m1;
When you use upcasting, the object is not changing. Nevertheless, when you
upcast an object, you will be able to access only member functions and data
members that are defined in the base class:

//It's ok

emp->FirstName;
emp->salary;

//Fails because upcasting is used

emp->getComm();

Example of upcasting usage


One of the biggest advantage of upcasting is the capability of writing generic
functions for all the classes that are derived from the same base class. Look
on example:

void congratulate(Employee* emp)

cout << "Happy Birthday!!!" << endl;

emp->show();

emp->addBonus(200);

};
This function will work with all the classes that are derived from the Employee
class. When you call it with objects of type Manager and Person, they will be
automatically upcasted to Employee class:

//automatic upcasting

congratulate(&c1);

congratulate(&m1);
Try to run this program:

Happy Birthday!!!
First Name: Kevin Last Name: Jones
Happy Birthday!!!
First Name: Steve Last: Name Kent
An example about how to use upcasting with virtual functions is described in
“C++ Polymorphism” topic.

Memory layout
As you know, derived class extends properties of the base class. It means
that derived class has properties (data members and member functions) of
the base class and defines new data members and member functions.

Look on the memory layout of the Employee and Manager classes:

Of course, this model is simplified view of memory layout for objects.


However, it represents the fact that when you use base class pointer to point
up an object of the derived class, you can access only elements that are
defined in the base class (green area). Elements of the derived class (yellow
area) are not accessible when you use base class pointer.

DOWNCASTING
Downcasting is an opposite process for upcasting. It converts base class
pointer to derived class pointer. Downcasting must be done manually. It
means that you have to specify explicit type cast.

Downcasting is not safe as upcasting. You know that a derived class object
can be always treated as base class object. However, the opposite is not
right. For example, a Manager is always a Person; But a Person is not always
a Manager. It could be a Clerk too.

You have to use an explicit cast for downcasting:


//pointer to base class object

Employee* emp;

//object of derived class

Manager m1("Steve", "Kent", 3000, 0.2);

//implicit upcasting

emp = &m1;

//explicit downcasting from Employee to Manager

Manager* m2 = (Manager*)(emp);
This code compiles and runs without any problem, because emp points to an
object of Manager class.

What will happen, if we try to downcast a base class pointer that is pointing
to an object of base class and not to an object of derived class? Try to
compile and run this code:

Employee e1("Peter", "Green", 1400);

//try to cast an employee to Manager

Manager* m3 = (Manager*)(&e1);

cout << m3->getComm() << endl;


e1 object is not an object of Manager class. It does not contain any
information about commission. That why such an operation can produce
unexpected results.

Look on the memory layout again:


When you try to downcast base class pointer (Employee) that is not actually
pointing up an object of derived class (Manager), you will get access to the
memory that does not have any information about derived class object
(yellow area). This is the main danger of downcasting.

You can use a safe cast that can help you to know, if one type can be
converted correctly to another type. For this purpose, use dynamic cast.

Dynamic Cast
dynamic_cast is an operator that converts safely one type to another type. In
the case, the conversation is possible and safe, it returns the address of the
object that is converted. Otherwise, it returns nullptr.

dynamic_cast has the following syntax

dynamic_cast<new_type> (object)
If you want to use dynamic cast for downcasting, base class should be
polymorphic – it must have at least one virtual function. Modify base class
Person by adding a virtual function:

virtual void foo() {}


Now you can use downcasting for converting Employee class pointers to
derived classes pointers.

Employee e1("Peter", "Green", 1400);

Manager* m3 = dynamic_cast<Manager*>(&e1);
if (m3)

cout << m3->getComm() << endl;

else

cout << "Can't cast from Employee to Manager" << endl;


In this case, dynamic cast returns nullptr. Therefore, you will see a warning
message.

You might also like