Documente Academic
Documente Profesional
Documente Cultură
Agenda
Inheritance & Polymorphism A short reminder File Handling in C++ Polymorphism, Files and Serialization
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(){} };
Base1 b();
var1
Derived1 d();
var1
var2
Polymorphism
Introduction
As we recall, a pointer to the base class can also point to objects from a derived class. There will be no data loss e.g.: CGraphicalItem* items[7];
CPoint CRect
CPoint
CLine CCircle
Polymorphism
Example
class Employee { double Salary; public: void Print() const {} void RaiseSalary (double r) { Salary += r; Print(); } }; class Manager : public Employee { public: void Print() {} };
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
Our goal in polymorphism is to avoid checking the actual type of an object by using virtual methods
copyrights Elhanan Borenstein
Polymorphism
General Containers
General Containers support the implementation of data structures using pointers to Data* while actually storing objects that are derived from Data. Examples: Humus, MFC objects (CObArray), Graphic objects
Generic Algorithms
Generic Algorithms form a skeleton of the algorithms by calling methods which will be implemented differently by each derived class. Example: Print, Draw Object, Calc3DVolume.
Polymorphism
Abstract Classes
There are cases (especially when we implement a General Container), where there is no intention to actually create an object of the base class. In such a case, we wish to:
1. 2.
Avoid implementation of some of the base class virtual methods (which will be overridden by the derived classes anyway). Prevent the programmer from creating objects of the base class. 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).
Example: abstract
Polymorphism
Try that
class A { public: virtual void f() {cout<<A;} void h() {cout<<a;} virtual void g() { f(); h(); } }; class B : public A { public: virtual void f() {cout<<B;} void h() {cout<<b;} }; main() { B* p; p = new C; p->g(); p->h(); }; class C : public B { public: virtual void f() {cout<<C;} void h() {cout<<c;} };
1. 2. 3. 4. 5.
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.)
Example: typeinfo
copyrights Elhanan Borenstein
Polymorphism
Dynamic Casting
Dynamic casting is a safe method to perform casting to a specific derived class while checking if it actually points to an object of that class. There are cases where dynamic_cast has an advantage over typeid. For example:
class A { }; class B : public A { void Do() {} }; class C ; public B { }; }
copyrights Elhanan Borenstein
C:
FILE* pfile; fwrite(pfile, array, size, );
C++:
ofstream out_file(); out_file.write(array, size, );
copyrights Elhanan Borenstein
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).
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). Borenstein copyrights Elhanan
tellg() / tellp() getting the position of the reading (get) / writing (put) marker
To read:
get() reading a single character of a buffer getline() reading a single line >> operator reading a object
Polymorphism, Files
and
Serialization
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.
Serialization in C++
Saving & Loading Objects
For each class we wish to be able to store, we 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.
Serialization in C++
21,000 ptr 20
h e l
l o \n
21,000
4 Bytes
5
4 Bytes
h e l
5 Bytes
l o
20
4 Bytes
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.
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
hr_db
2 ptr ptr ptr
ptr 23.5
B e n \n
ptr 410.5 10
B i
l \n
e m
B e n 23.5 m a
B i
l l 410.5 10
Questions?
copyrights Elhanan Borenstein