Transcript OOP

Object Oriented
Programming
Lecture #8
Elhanan Borenstein
[email protected]
copyrights © Elhanan Borenstein
Agenda

Inheritance & Polymorphism – A short reminder

File Handling in C++

Polymorphism & Files: Serialization
copyrights © Elhanan Borenstein
Inheritance & Polymorphism
a Short Reminder
copyrights © Elhanan Borenstein
Inheritance
Example
class Base1
{
int var1;
public:
Base1() {…} // constructor
void OldFunc() {…}
void Init() {…}
};
class Derived1 : [public|protected|private] Base1
{
int var2;
public:
Derived1() {…} // constructor
void Init() {…} // override
void Do(){…}
};
copyrights © Elhanan Borenstein
Inheritance
The Logic behind Inheritance

When inheriting a class, we inherit all
its members and they will be included
in the derived class: Base (father)
Additions

Somewhat similar to object data
members (embedded):
Derived (son)  (SIZE?)
inner object
Additions

embedding
class
To differentiate, we can check the logics behind the
implemented entities:

Inheritance: The derived class is a type of the base class.

Inner class: The inner class is a part of the external class.
copyrights © Elhanan Borenstein
Inheritance
Understanding Inheritance - Example
class GraphicItem
{
int color;
public:
GraphicItem() {…} // constructor
void Draw() {…}
void ChangeColor(int n_clr) {…}
};
…
class CPoint : public GraphicItem
{
int m_x, m_y;
public:
CPoint() {…} // constructor
void Draw() {…} // override
void Align(){…}
};
P = G;
GraphicItem G, *pG;
CPoint
P, *pP;
…
G = P;
pG = pP;
pP = pG;
…
copyrights © Elhanan Borenstein
Inheritance
Accessing the Base Class Data Members

All the data members of the base class also exists in the
derived class. But there are cases where we cannot access
these members.

Hiding (but we can still use the full name (base_class::member)

Private Permission (but we can still use public methods for access)
Using the Base Class Member Functions

The derived class also inherit all the base class methods.

The derived class can override inherited methods


We can still activate the base method using its full name.
C’tor, D’tor and C.C. are the only methods that have a
different behavior when inherited.
copyrights © Elhanan Borenstein
Polymorphism
Introduction

The Polymorphism mechanism allows for an action to
performs differently according to the object type, while
being transparent to the programmer.

As we recall, a pointer to the base class can also point to
objects from a derived class.


There will be no data loss

We will be able to activate methods on that object, only if they exist
in the base class.
The issue is however, which method will be activated
(base or derive)?
copyrights © Elhanan Borenstein
Polymorphism
Example
class Employee
{
double Salary;
public:
void Print() const {…}
void RaiseSalary (double r)
{
Salary += r;
Print();
}
};
main ()
{
class Manager : public Employee
{
…
public:
void Print() {…}
};
}
Employee *pE;
pE = new Manager;
pE->Print();
…
Manager m;
m.Print();
m.RaiseSalary();
copyrights © Elhanan Borenstein
Polymorphism
Virtual Methods and Dynamic Binding

When activating a method through a pointer to the
base class:

if the method was not defined as virtual:



A Static Binding is performed (on compilation)

The base class method will be activated
If the method was define as virtual:

A Dynamic Binding will be performed (on runtime)

The method of the appropriate class will be activated.
Usage: Containers, Generic Algorithms
copyrights © Elhanan Borenstein
Polymorphism
Abstract Classes

There are cases (especially when we implemented a
General Container), where there is no intention to actually
create an object of the base class.

In such a case, we wish to:


Avoid implementation

Prevent the programmer from creating objects of the base class.
The solution is Pure Functions and Abstract Classes:

A pure function is a virtual function, declared in the base class
only for the purpose of implementing it in the derived classes.
To define a function as pure we will add =0 in the prototype.

A class with one or more pure function is automatically an abstract
class  objects of that class cannot be created or passed ByVal.
copyrights © Elhanan Borenstein
Polymorphism
How Does Dynamic Binding Work?

Dynamic binding is implemented by a virtual functions table.

Each object that includes a virtual function will also include
a pointer to this table (usually two bytes pointer):

Calling a virtual function will thus require two memory calls:
class A
{
int a;
public:
virtual void f() {…}
virtual void h() {…}
virtual void g() {…}
};
class B : public A
{
int b;
public:
virtual void g() {…}
};
class C : public B
{
int c;
public:
virtual void h() {…}
};
C vftable
C obj; 
a
vfptr
b
c
A::f()
B::g()
C::h()
copyrights © Elhanan Borenstein
Polymorphism
Runtime Type Information

There are scenarios where we are required to check what
is the real object type that we actually hold. (WHEN?)

We can implement our own mechanism using a virtual
function called Type().

Alternatively, the operator typeid can be used.

#include <typeinfo.h> is required (not an integral part of C++)

Setting the project to work with RTTI is required

The return value is an object of type typeinfo, that supports the
method name() and the operator ==

typeid also works on fundamental data types (int, float, etc.)
copyrights © Elhanan Borenstein
File Handling in C++
copyrights © Elhanan Borenstein
File Handling Classes
Working with Files

C++ includes special classes for file handling (reading
from files / writing to files).

We already had a short example where these classes
were used (when overloading the operator >>:

ostream – writing to the screen

ofstream – writing to a file

C file handling functions (fopen, fprintf, fread, fwrite) can
still be used.

NOTE:

C file handling functions : “global” functions that get a parameter of
type FILE*

C++ file handling functions : methods of a class which represents a
file
copyrights © Elhanan Borenstein
File Handling Classes
General


When working with files in C++, the following classes can
be used:

ofstream – writing to a file

ifstream – reading for a file

fstream – reading/writing (multiple inheritance)

…and many other derived and base classes…
What does it all have to do with cout?

ofstream inherits from the class ostream (standard output class).

ostream overloaded the operator >> for standard output.

…thus an ofstream object can use methods and operators defined
in ostream (as we seen in the example).

When ever we include <iostream>, an ostream object, pointing to
stdout is automatically defined – this object is cout.
copyrights © Elhanan Borenstein
File Handling Classes
Hierarchy Diagram
copyrights © Elhanan Borenstein
File Handling Classes
Opening a File

A file can be open by the method “open()” or immediately
in the c’tor (the natural and preferred way).

void ofstream / ifstream::open(const char* filename, int mode, int prot);

filename – file to open (full path or local)

mode – how to open (one or more of the following – using | )



ios::app – append

ios::ate – open with marker at the end of the file

ios::in / ios::out – (the defaults of ifstream and ofstream)

ios:nocreate / ios::noreplace – open only if the file exists / doesn’t exist

ios::trunc – open an empty file

ios::binary – open a binary file (default is textual)
prot – file type (read only, hidden, etc.)
Don’t forget to close the file using the method “close()”
copyrights © Elhanan Borenstein
File Handling Classes
Querying a File

is_open() – Checking whether the file was open correctly.
(for compatibility with C, the operator ! was overloaded).

rd_state() – returns a variable with one or more (check
with AND) of the following options:

ios::goodbit – OK

ios::eofbit – marker on EOF

ios::failbit – illegal action, but alright to continue

ios:badbit – corrupted file, cannot be used.

We can also access the bit we wish to check with eof(),
good(), fail(), bad().

clear() is used to clear the status bits (after they were
checked).
copyrights © Elhanan Borenstein
File Handling Classes
Moving within the File

seekg() / seekp() – moving the reading (get) / writing (put)
marker


two parameters: offset and anchor
tellg() / tellp() – getting the position of the reading (get) /
writing (put) marker
copyrights © Elhanan Borenstein
File Handling Classes
Reading /Writing from/to Textual Files


To write:

put() – writing single character

<< operator – writing an object
To read:
#include <fstream.h>
main()
{
// Writing to file
ofstream OutFile("my_file.txt");
OutFile<<"Hello "<<5<<endl;
OutFile.close();

get() – reading a single
character of a buffer
int number;
char dummy[15];

getline() – reading a single line

>> operator – reading a object
// Reading from file
ifstream InFile("my_file.txt");
InFile>>dummy>>number;
InFile.seekg(0);
InFile.getline(dummy, sizeof(dummy));
InFile.close();
}
copyrights © Elhanan Borenstein
File Handling Classes
Reading /Writing from/to Binary Files

To write n bytes:


write (const unsigned char* buffer, int n);
To read n bytes (to a pre-allocated buffer):

read (unsighed char* buffer, int num)

Use: int gcount() to check how many byte where actually read (WHY)

Note: Unlike C, the buffers are of type unsigned char* (and not void*)
#include <fstream.h>
main()
{
int array[] = {10,23,3,7,9,11,253};
ofstream OutBinaryFile("my_b_file.txt“, ios::out | ios::binary);
OutBinaryFile.write((char*) array, sizeof(array));
OutBinaryFile.close();
}
copyrights © Elhanan Borenstein
Polymorphism & Files
Serialization
copyrights © Elhanan Borenstein
Serialization
Introduction

Serialization is a common method to store (save) and
retrieve (load) data objects. It can be used to save
database records, the status of the application, etc.

In C:


we could store all the required fields in structures and then use
fread/fwrite to store this data in a binary file.

Important – pointers should not be stored (as they will be invalid
when we load them. Instead, whenever a dynamic allocation was
used, the file should store the size of the allocation and then the
content (and load appropriately).
In C++: the same mechanism is use but naturally using
Classes, Polymorphism and Object Oriented paradigm.
copyrights © Elhanan Borenstein
copyrights © Elhanan Borenstein
Serialization in C++
Saving & Loading Objects


Each class we wish to be able to store, will have a Save()
method (this method will handle saving the object data members to the file).

Save() will get as parameter an object of type ofstream.

If the object includes dynamic allocations, it should not store the
pointer, but rather the size of the allocated memory and its content.

Note: if the class includes (or inherits) virtual functions, the pointer
to the vf table should not be saved.

A derived class can (and should) use the base class Save method
(e.g. base_name::Save()) to store the base data members and only
then save the new derived members.
Each such class will also have:

A Load C’tor that gets as a parameters an object of type ifstream
and builds a new object according to the data in the file

A Load() method that can read the data to an existing object.

When loading a dyn. allocated member, a new allocation is made.
Serialization in C++
Using Containers


When using a general container (which holds objects of
various classes with a common base class)

we wish to be able to use the Save() method transparently. Thus,
we will define the Save() method in the base class as virtual.

The container should also implement a Save() method which will
traverse all the objects it holds and call their Save() method.
What about the container Load() method?

The container has to “know” which objects should be created.

It is thus common to store in the file, before each object a code
(textual, binary, etc.) which will identify the object type. The container
Load() method, will first read this code and then create the
appropriate object.

Branching should be performed wisely (switch, hash table, etc.)
copyrights © Elhanan Borenstein
Serialization in C++
Example

We wish to implement a data base which will allow the user
to input / print / save / load the list of employees in the
company.

For each employee in the company we wish to store:


Name (char*), Salary (float)
Some of the employees are managers. Manager record
should also include:

Level (int)

Obviously, we wish to have as little as possible locations
where we distinct between employees and managers.

Example: Human Resources – Data Base
copyrights © Elhanan Borenstein
Questions?
copyrights © Elhanan Borenstein