Object Oriented Programming Elhanan Borenstein [email protected] Lecture #8 copyrights © Elhanan...
-
Upload
bernard-hodge -
Category
Documents
-
view
223 -
download
2
Transcript of Object Oriented Programming Elhanan Borenstein [email protected] Lecture #8 copyrights © Elhanan...
Object OrientedProgramming
Elhanan Borenstein
Lecture #8
copyrights © Elhanan Borenstein
Agenda Inheritance & Polymorphism – A short reminder
File Handling in C++ Polymorphism & Files: Serialization
copyrights © Elhanan Borenstein
Inheritance & Polymorphisma Short Reminder
copyrights © Elhanan Borenstein
InheritanceExample
class Base1 {
int var1; public:
Base1() {…} // constructorvoid OldFunc() {…}void Init() {…}
};
class Derived1 : [public|protected|private] Base1{
int var2; public:
Derived1() {…} // constructorvoid Init() {…} // overridevoid Do(){…}
};copyrights © Elhanan Borenstein
Inheritance
When inheriting a class, we inherit all its members and they will be included in the derived class:
Somewhat similar to object data members (embedded):
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.
The Logic behind Inheritance
Base (father)
AdditionsDerived (son) (SIZE?)
Additions
embeddingclass
inner object
copyrights © Elhanan Borenstein
InheritanceUnderstanding Inheritance - Example
class GraphicItem {
int color; public:
GraphicItem() {…} // constructorvoid Draw() {…}void ChangeColor(int n_clr) {…}
};
class CPoint : public GraphicItem{
int m_x, m_y; public:
CPoint() {…} // constructorvoid Draw() {…} // overridevoid Align(){…}
};
…
GraphicItem G, *pG;CPoint P, *pP;…
G = P;
P = G;
pG = pP;
pP = pG;
…
copyrights © Elhanan Borenstein
Inheritance
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)
Accessing the Base Class Data Members
copyrights © Elhanan Borenstein
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.
Using the Base Class Member Functions
Polymorphism
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)?
Introduction
copyrights © Elhanan Borenstein
PolymorphismExample
class Employee{
double Salary; public:
void Print() const {…}void RaiseSalary (double r){
Salary += r;Print();
}};
class Manager : public Employee{
… public:
void Print() {…} };
main (){
Employee *pE;pE = new Manager;pE->Print();…
Manager m;m.Print();m.RaiseSalary();
}
copyrights © Elhanan Borenstein
Polymorphism
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
Virtual Methods and Dynamic Binding
copyrights © Elhanan Borenstein
Polymorphism
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.
Abstract Classes
copyrights © Elhanan Borenstein
Polymorphism
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:
C obj;
How Does Dynamic Binding Work?
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() {…}};
avfptr
bc
A::f()B::g()C::h()
C vftable
copyrights © Elhanan Borenstein
Polymorphism
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.)
Runtime Type Information
copyrights © Elhanan Borenstein
File Handling in C++
copyrights © Elhanan Borenstein
File Handling Classes
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
Working with Files
copyrights © Elhanan Borenstein
File Handling Classes
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.
General
copyrights © Elhanan Borenstein
File Handling ClassesHierarchy Diagram
copyrights © Elhanan Borenstein
File Handling Classes
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()”
Opening a File
copyrights © Elhanan Borenstein
File Handling Classes
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).
Querying a File
copyrights © Elhanan Borenstein
File Handling Classes
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
Moving within the File
copyrights © Elhanan Borenstein
File Handling Classes
To write: put() – writing single character << operator – writing an object
To read: get() – reading a single
character of a buffer getline() – reading a single line >> operator – reading a object
Reading /Writing from/to Textual Files
copyrights © Elhanan Borenstein
#include <fstream.h>main(){
// Writing to fileofstream OutFile("my_file.txt");OutFile<<"Hello "<<5<<endl;OutFile.close();
int number;char dummy[15];
// Reading from fileifstream InFile("my_file.txt");InFile>>dummy>>number;
InFile.seekg(0);InFile.getline(dummy, sizeof(dummy));InFile.close();
}
File Handling Classes
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*)
Reading /Writing from/to Binary Files
copyrights © Elhanan Borenstein
#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();
}
Polymorphism & Files
Serialization
copyrights © Elhanan Borenstein
Serialization
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.
Introduction
copyrights © Elhanan Borenstein
Serialization in C++
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.
Saving & Loading Objects
copyrights © Elhanan Borenstein
Serialization in C++
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.)
Using Containers
copyrights © Elhanan Borenstein
Serialization in C++
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
Example
copyrights © Elhanan Borenstein
Questions?
copyrights © Elhanan Borenstein