object oriented programming language by c++
DESCRIPTION
slides cane make your under standing for the OOP "useing c++ " essayer than any other slides by :dr.wa'ael al qassas edited by mohamad al maaneTRANSCRIPT
Object Oriented Object Oriented ProgrammingProgramming
قصاص وائل 1
Course OutlineCourse Outline
Introduction to Object Oriented Programming (OOP):
Overview of programming languages. * What is object Oriented? * Benefits of Object Oriented. * What is an object? * What is a class? * Black boxes and interfaces. * Attributes and methods. * What is abstract class (abstraction)?
classes Class fundamentals. * A closer look at class member access.
* Constructors and destructors. * Parameterized constructors. * Classes and structures are related. * Unions and classes are related. * Inline functions. * Creating inline functions inside a class. * Arrays of object. * Pointers to object. * Object references.
قصاص وائل 2
Friend functions Friend functions. * Overloading constructor functions. * Dynamic
initialization. * Assigning objects. * Passing objects to functions. * Returning objects. * Creating and using copy constructor. * The this keyword.
Operator Overloading Operator Overloading using member functions. * Friend operator
functions. * A closer look at the assignment operator. * Overloading new and delete. * Overloading []. * Overloading other operators.
Inheritance Introducing inheritance. * Base class access control. * Using protected
members. * Inheriting Multiple Base Classes. * Constructors, destructors, and inheritance. * Granting access. * Virtual base class.
Virtual functions and polymorphism Pointers to derived class. * Virtual functions. * Virual functions are
inherited. * Pure virual functions and Abstract classes. * Early versus late binding.
Templates and Exception handling Generic functions. * A function with two generic types. * Exception
handling. * Options for exception handling. * Generic classes. * Eception Handling. * Using Multiple catch statements. * Catching all exceptions.
Text book and references Text book and references
Title : C++ How to Program Author(s) Paul J. Deitel, Harvey M. Deitel Edition : 4th Publisher : Prentice Hall**********************************************************
***
Title : C++ From the GROUND UP Author(s) R. Schildt Edition: 3rd Pubisher: McGraw-Hill
قصاص وائل 4
Grading Policy Grading Policy قصاص وائل 5
• First Exam 15 • Second Exam 15 • Lab 20 • Final Exam 50
Classes and Data Abstraction Classes and Data Abstraction
A class is a logical method to organize data and operations (functions) on that data in the same unit
(called class). They are declared using keyword class, functionality is similar to that of the C
keyword struct with some difference. Its general form is:
class class_name { permission_label_1: member1;
permission_label_2: member2;
... } object_name;where class_name is a name for the class (user
defined type) and the optional field object_name is one, or several, valid object identifiers.
The body of the declaration can contain members, that can be either data or function
declarations, and optionally permission labels, that can be any of these three
keywords: private:, public: or protected:. A reference to the permission which the following
members acquire: private members of a class are accessible only
from other members of their same class or from their "friend" classes.
protected members are accessible from members of their same class and friend classes, and also from members of their derived classes.
public members are accessible from anywhere the class is visible.
قصاص وائل 7
When declaring members of a class before including any permission label, the members are
considered private, since it is the default permission that the members of a class declared
with the class keyword acquire. For example: class CRectangle {
int x, y; //x,y are considered private members
public: void set_values (int,int); int area (void); } rect;
قصاص وائل 8
Declares class CRectangle and an object called rect with four members: two variables of type int (x and
y) in the private section (because private is the default permission) and two functions in the public
section: set_values() and area(), of which only the prototype are included.
Any of the public members of the object rect could be referred to just by putting the object's name followed by a point and then the class member
rect.set_value(3,4);myarea = rect.area();
but it is not possible to refer to x or y since they are private members of the class and they could only be referred to from other members of that same class.
قصاص وائل 10
The operator :: of scope (called scope of resolution) included in the definition of
set_values(). It is used to declare a member of a class outside it. Notice that we have defined the behavior of function area() within the definition
of the CRectangle class given its extreme simplicity. Whereas set_values() has only its
prototype declared within the class but its body definition is outside. In this outside declaration
we must use the operator of scope :: The scope operator (::) specifies the class to
which the member being declared belongs.
قصاص وائل 11
The reason why x and y are made private members is because sometimes it is important that values
cannot be modified in an unexpected way from outside the class (i.e. via client code). To access
these variables this can be done through member functions that are declared as public.
In the previous example, we have already defined a function to introduce those values in the object
(set_values()) and therefore the rest of the program does not have a way to directly access them.
Several different objects can be defined from one class.
قصاص وائل 12
ExampleExample#include< iostream.h>#include <cstring>class student {
char name[20];int First,second,final,total,ID;
int calculate_total( );
public:student() { strcpy(name,"AHMAD"); ID=900901123; First=second=final=0; }
int get_total(){return total;}void print(void){cout<<name<<"\t"<<ID<<"\t"<<calculate_total( )<<endl;}
}; // end of class definition
int student::calculate_total( ){total=First+second+final;return total;}
قصاص وائل 13
void main(){student st; cout<<st.get_total(); st.print(); st.print();}
قصاص وائل 14
قصاص وائل 15
The call to rect.area( ) does not give the same result as the call to rectb.area( ), each object of class
CRectangle has its own variables x and y, and its own functions set_value() and area(). functions are properties of the object, instead of the usual view of
objects as function parameters in structured programming. In this concrete case, the class (type of
object) is CRectangle, of which there are two instances, or objects: rect and rectb, each one with its own member variables and member
functions.
QuizQuizDesign a class named Student that has a
name, ID, first,second, final and Total marks.
This class has a calculate_total method which is has a private permission
The class has set_Name_ID( char[ ],int) method that stores the name of the student
The class has set_marks(int,int,int) methodThe class has print( ) method that calls the
calculate_total and then prints the student name , student ID and student total mark.
The main function looks like this:void main( ){Student St;St.set_Name_ID(“Ahmad”,1000901123);St.set_marks(19,21,41);St.print( ); }
قصاص وائل 16
// Example on class 22-feb-2012#include< iostream.h>#include <cstring>class Student {
char name[20];int first,second,final,total,ID;
void calculate_total( );
public:void Set_Name_ID(char n[ ],int id){ strcpy(name,n);ID=id;}
void Set_marks(int ,int ,int );
void print(void){ calculate_total( );
cout<<name<<"\t"<<ID<<"\t"<<total<<endl;}}; // end of class definition
قصاص وائل 17
Example:Example:
void Student::calculate_total( ){total=first+second+final;}
void Student::Set_marks(int x,int y,int z){ first=x;
second=y;final=z;}
void main( ){Student St;St.Set_Name_ID("Ahmad",1000901123);St.Set_marks(19,21,41);St.print( ); }
قصاص وائل 18
Example:Example:
Constructors and Destructors Constructors and Destructors
Objects generally need to initialize variables or assign dynamic memory during their process of
creation to become totally operative and to avoid returning unexpected values during their execution. what would happen if in the previous example the
function area() is called before having called function set_values? Probably an undetermined
result since the members x and y would have never been assigned a value.
In order to avoid that, a class can include a special function: a constructor, which can be declared
by naming a member function with the same name as the class. This constructor function will be called automatically when a new instance
of the class is createdقصاص وائل 19
“A construc
tor never returns a value nor does the
void have to
be specified
”
Example:Example:
For the student example add a constructor method that prints a message indicating that an object has been constructed.
قصاص وائل 21
Example on Example on ConstructorsConstructors
class Student {char name[20];int first,second,final,total,ID;
void calculate_total( ); public:
Student( ){ cout<<"An object has been constructed\n";}
void Set_Name_ID(char n[ ],int id){ strcpy(name,n);ID=id;}
void Set_marks(int ,int ,int );
void print(void){ calculate_total( );
cout<<name<<"\t"<<ID<<"\t"<<total<<endl;}}; // end of class definition
قصاص وائل 22
void Student::calculate_total( ){total=first+second+final;}
void Student::Set_marks(int x,int y,int z){ first=x;
second=y;final=z;}
void main( ){Student St;St.Set_Name_ID("Ahmad",1000901123);St.Set_marks(19,21,41);St.print( ); }
قصاص وائل 23
Example:Example:
Modify the constructer so that it gives a default values to name “ No name”, ID=0, first,second and final are also 0
Student( ){strcpy(name,”No name”) ;ID=0;first=second=final=0;}
قصاص وائل 24
Overload the constructor so it can take the name and the ID at the creation of the instance.
Also let id has a default value equal to zero
Student (char n[ ],int id=0){ strcpy(name,n);
ID=id; first=second=final=0;}
In the main
Student St2("Ali");St2.print();
قصاص وائل 25
Empty ConstructorEmpty ConstructorIf we didn’t define a constructor then there is
an empty constructor as defaultAlso there is a default copy_constructor that
allow copying one constructor to another.
void main( ){Student St1;St1.print();St1.Set_Name_ID("Ahmad",1000901123);St1.Set_marks(19,21,41);St1.print( ); Student St2;St2=St1;St2.print();}
قصاص وائل 26
Example:Example:
With no constructors, the compiler automatically assumes that it has empty constructor:
Empty constructor: It is a constructor with no parameters defined as empty block of instructions. It does nothing. The empty construction exists only if no other constructor is explicitly declared. In case
that any constructor with any number of parameters is declared, the default constructor is not called.
CExample::CExample () { };To copy one instance of class to another, Copy
constructor is needed: when ever one object assigned to another we are making a copy of it.
There are two types of copy constructor. ◦ Perform simple variable by variable
assignment: copy of all the components of one object to another.
◦ Passing an object to a function. It is a constructor with one parameter of same type that assigns to every non-static class member variable
of the object a copy of the passed object.
CExample::CExample (const CExample& rv)
create a new object of class CExample (rv) {a=rv.a; b=rv.b;
c=rv.c;} In the example above, a new object
of class CExample is created and which is a copy of the passed object, then in the implementation part will
initialize the data members of the current object with the rv data
members. قصاص وائل 28
Overloading Constructors Overloading Constructors
A constructor can also be overloaded with several functions that have the same name but
different types or numbers of parameters. In the cases where a class is declared and no
constructor is specified, the compiler automatically assumes two overloaded
constructors ("default constructor" and "copy constructor"). For example, for the class:
class CExample { public: int a,b,c;
void multiply (int n, int m) { a=n; b=m; c=a*b; }
};قصاص وائل 29
قصاص وائل 30
Example:Example:
In this case rectb was declared without parameters, so it has been initialized with
the constructor that has no parameters, which declares both width and height
with a value of 5. Notice that if we declare a new object and we do not want to pass
parameters to it we do not include parentheses ( ):
CRectangle rectb; // right CRectangle rectb(); // wrong
قصاص وائل 31
Destructor Destructor The Destructor is automatically called
when an object is released from the memory in two cases:
1. Its scope of existence has finished (i.e, if it was defined as a local object within a function and the function ends)
2. Object dynamically assigned and it is released using delete operator.
The destructor must have the same name as the class with a tilde (~) as prefix.
Destructor receives no parameter and returns no value.
A class may have only one destructor. The use of destructors is specially suitable
when an object assigns dynamic memory.
Build a Destructor that prints a messege denoting when an object is being distructed
~Student(){cout<<name<<"\nAn object has been
destructed\n";}
قصاص وائل 33
Example on destruction Example on destruction void F(Student S){Student S1;S1=S;S.Set_marks(25,25,50);S.print();S1.print();}
void main( ){Student St1,St2;St1.Set_Name_ID("Ahmad",1000901123);St2.Set_Name_ID("Ali",1000902321);F(St1);cout<<"back from function\n";}
قصاص وائل 34
new , delete keywordsnew , delete keywords
The new keyword allocate memory dynamically at run time , so that the records are allocated while execution
There is a direct relationship between new and pointer.
قصاص وائل 35
#include <iostream.h>void main(){ int *p1, *p2;
p1=new int;*p1=10;cout<<&p1<<endl; // location of the pointercout<<"Memory location "<<p1<<" contains " <<*p1<<endl;p2=new int;*p2=10;cout<<&p2<<endl; // location of the pointercout<<"Memory location "<<p2<<" contains "<<*p2<<endl;delete p1;delete p2;
}قصاص وائل 36
Example:Example:
OutputOutput
0x0012FF7CMemory location 0x00901F80 contains
100x0012FF78Memory location 0x00901D20 contains
10Press any key to continue
قصاص وائل 37
#include <iostream.h>void main(){ int *p1, *p2;
p1=new int;*p1=10;cout<<&p1<<endl; // location of the pointercout<<"Memory location "<<p1<<" contains " <<*p1<<endl;delete p1;p2=new int;*p2=10;cout<<&p2<<endl; // location of the pointercout<<"Memory location "<<p2<<" contains "<<*p2<<endl;delete p2;}
قصاص وائل 38
Example:Example:
0x0012FF7CMemory location 0x00901F80 contains
100x0012FF78Memory location 0x00901F80 contains
10Press any key to continue
قصاص وائل 39
// example on constructors and destructors#include <iostream.h>class CRectangle { int *width, *height; public: CRectangle (int,int); // constructor
~CRectangle (); //destructor
int area (void) {return (*width * *height);} }; CRectangle::CRectangle (int a, int b) { width = new int; height = new int; *width = a; *height = b;} CRectangle::~CRectangle () { delete width; delete height;} int main () { CRectangle rect (3,4), rectb (5,6); cout << "rect area: " << rect.area() << endl; cout << "rectb area: " << rectb.area() << endl;
return 0;}
قصاص وائل
40
Example:
Inline functions Inline functions
An inline function is a function that is expanded in line at the point at which it is invoked, instead of actually being called. The reason for inline function is efficiency. There are two ways to create an inline function.
The first : to use the inline modifier. inline int f(){ //……..}
قصاص وائل 41
Every time a function is called, a series of instructions must be executed, both
to set up the function call, including pushing any arguments onto the stack,
and to return from the function. In some cases, many CPU cycles are used to perform these procedures. However, when a function is expanded in line, no
such overhead exists, and the overall speed of your program will increase.
Where the inline function is large, the overall size of your program will also
increase. For this reason, the best inline functions are those that are very
small. قصاص وائل 42
exampleexample
class c1 {int i;
public:int get_i();void put_i(int j);};
inline int c1::get_i() { return i;}inline void
c1::put_i(int j) { i=j;}
void main(){c1 s;
s.put_i(10);cout<<s.get_i();}
output10
If you compile this version of the
program, save its object code, and then compile it again with
the inline specifier removed, you will see
the inline version is several bytes smaller.
Inline is a request not a command, that the
compiler generate inline code.
Some compilers will not generate inline
code if a function contains a loop, a switch, or a goto.
no inline recursive functions.
Inline functions that contain static variables
are disallowed.
Second :Creating Inline Functions inside a ClassAny function that is defined inside a class definition is
automatically made into an inline function. It is not necessary to precede its declaration with the keyword
inline.
قصاص وائل 44
class c1 {int i;
public://automatic inline functions.int get_i() {return i;}void put_i(int j) {i=j;} };
int main(){ c1 s;
s.put_i(10);cout<<s.get_i();return 0;}
Output10
Face book groupFace book group
www.facebook.com/groups/oop.aabu/
قصاص وائل 45
Enumeration in C++Enumeration in C++
The keyword enum creates a user-defined type
Examples:enum semesters {first, second, summer};enum months{jan=1,feb,mar,apr,may,jun,jul,aug,sept,
oct,nov,dec};
If you print enum variable, the output will be an integer that represents the order of the value in the definition starting from 0
For the second example the counting will start from 1You cant read an enum by cinYou cant make arithmatic operations on enumYou can only assign a value for the enum by using = ,
and make relational operations on enum
قصاص وائل 46
#include <iostream.h>void main(){
enum mark {pass, fail};mark m;int score;cout<<"Enter your mark ";cin>>score;if (score>=50) m=pass;else
m=fail;
if( m==pass) cout<<" you passed the exam\n";else cout<<"you failed in the exam\n";
}
قصاص وائل 47
Example:Example:
3.3 Array of object and Pointers to 3.3 Array of object and Pointers to Objects Objects
Array of objects can be created in the same way that you create arrays of any other data types.
قصاص وائل 48
قصاص وائل 49
It is perfectly valid to create pointers
pointing to classes, in order to do that,
simply consider that once declared, the class becomes
a valid type, so use the class name as
the type for the pointer.
قصاص وائل 50
Example:Example:
(*p).show_num(); and p->show_num(); are the same*p can be read: pointed by p&x can be read: address of xx.y can be read: member y of object x(*p).y can be read: member y of object
pointed by pp->y can be read: member y of object
pointed by p (equivalent to the previous one)x[0] can be read: first object pointed by xx[1] can be read: second object pointed by
xx[n] can be read: (n+1)th object pointed by
x
قصاص وائل 51
#include <iostream.h>class p_example {
int num;public: p_example(int a){num=a;} void set_num(int val) {num=val;} void show_num( );}; void p_example::show_num() {cout<<num<<“\n”;}
void main(){ p_example ob[2]={10,20};
ob[0]. show_num(); ob[1]. show_num();}
10 20
قصاص وائل
52
If there is array of objects are to be defined, and there exist a constructor,
then the declaration will be:class_name obj[n]={values of
initialization}
Example:
Another Another example example on arrayon array
class Student {char name[20];int first,second,final,total,ID;
public:Student( ) //constructor
{strcpy(name,"No name") ; ID=0; first=second=final=0;}
Student(char n[ ],int id) //constructor overloading{strcpy(name,n) ; ID=id; first=second=final=0;}
void print(void){cout<<name<<"\t"<<ID<<"\t"<<total<<endl;}}; // end of class definition
قصاص وائل 53
void main( ){Student S1("Ali",123),S2("Ahmad",456);
Student St[3]={S1,S2};for (int i=0;i<3;i++) St[i].print();}
قصاص وائل 54
Example:Example:
Rewrite the main in the prev. Rewrite the main in the prev. example with pointersexample with pointers
void main( ){Student S1("Ali",123),S2("Ahmad",456), *SP;
Student St[3]={S1,S2};SP=St;for (int i=0;i<3;i++) (SP+i)->print();}
قصاص وائل 55
Example:Example:
Rewrite the main in the prev. Rewrite the main in the prev. example with pointersexample with pointers
void main( ){Student S1("Ali",123),S2("Ahmad",456), *SP;
Student St[3]={S1,S2};SP=St;for (int i=0;i<3;i++) SP++->print();}
قصاص وائل 56
Example:Example:
Static Class MemberStatic Class Member
Each object has its own copy of all data members of the class.
If a data item in a class defined as static, then only one such item is
created for the entire class, no matter how many objects there are.
قصاص وائل 57
// Example on class 29-feb-2012#include< iostream.h>#include <cstring>class Student { static int count;
char name[20];int first,second,final,total,ID;
public:Student( ) //constructor
{strcpy(name,"No name") ; ID=0; first=second=final=0; count++; cout<<"Numbers of students constructed :"<<count<<endl;}
}; // end of classint Student::count=0;
void main( ){ cout<<"\nConstruct 2 objects\n";
Student S1,S2;cout<<"\nConstruct 3 objects\n";Student St[3]; } // end of main
قصاص وائل 58
Example:Example:
The Output will be:The Output will be:
Construct 2 objectsNumbers of students constructed : 1Numbers of students constructed : 2
Construct 3 objectsNumbers of students constructed : 3Numbers of students constructed : 4Numbers of students constructed : 5Press any key to continue
قصاص وائل 59
Example:Example:
#include <iostream.h>
class st_example {static int count;
public:st_example (){count++;}int get_count(){return count;}};
int st_example::count=0;
void main(){ st_example ob1; cout<<”\n count
is”<<ob1.get_count(); st_example ob2; cout<<”\n count
is”<<ob1.get_count(); cout<<”\n count
is”<<ob2.get_count();st_example ob3;
cout<<”\n count is”<<ob3.get_count(); }
قصاص وائل 60
count is1 count is2 count is2 count is3
Static Member FunctionStatic Member Function
This type of function can be accessed in two ways:
1. Through any object of that class (ob1.get_count()).2. Or through the class name using the binary scope of
resolution (::) directly (cout<<st_example ::get_count();).
قصاص وائل 61
class Student { static int count;char name[20];int first,second,final,total,ID;
public:static void print_count(){cout<<“Students constructed: “
<<count<<endl;}Student( ) //constructor
{strcpy(name,"No name") ; ID=0; first=second=final=0; count++; print_count(); }}; // end of class
int Student::count=0;
void main( ){ Student::print_count();
cout<<"\nConstruct 2 objects\n";Student S1,S2;cout<<"\nConstruct 3 objects\n";Student St[3];}
قصاص وائل 62
OutbotOutbot
Numbers of students constructed : 0
Construct 2 objectsNumbers of students constructed : 1Numbers of students constructed : 2
Construct 3 objectsNumbers of students constructed : 3Numbers of students constructed : 4Numbers of students constructed : 5Press any key to continue
قصاص وائل 63
Example:Example:
#include <iostream.h>
class st_example {static int count;
public:st_example (){count++;}static int get_count(){return count;}};
int st_example::count=0;
void main(){ st_example ob1; cout<<”\n count
is”<<ob1.get_count(); st_example ob2; cout<<”\n count is”<<
st_example ::get_count(); cout<<”\n count
is”<<ob2.get_count(); st_example ob3; cout<<”\n count
is”<<ob3.get_count(); }
قصاص وائل 64
count is1 count is2 count is2 count is3
Constant Object Constant Object & &
Constant Member FunctionConstant Member Function
The keyword const is used in C language to define a data values that cannot be
changed during program execution. In OOP, const could be used to specify
constant object and / or constant member function.
قصاص وائل 65
#include <iostream.h>class time {private:int h,m,s;public:
void print() const; //constant function time(int i, int j, int k){h=i; m=j; s=k;}};void main(){ const time noon(12,0,0); //constant
object: }
قصاص وائل 66
Keyword const is used to specify non modifiable objects, and any attempt to modify the const object cause syntax
error. const time noon(12,0,0);// indicates constant object noon
of class time which is initialized to 12 noon.
Constant Member Function Constant Member Function Constant function could be defined as follows:
At prototype: type function_name() const ;
At implementation : type function_name() const { };
Notes: * It is not allowed for any member_function calls for const object unless the member functions also constant.
* Constant member functions cannot modify the object.
* It is not allowed to declare constructors as constant since it allow to modify objects
قصاص وائل 67
Example:Example:
#include <iostream.h>class time {private:int h,m,s;public:
void print() const {cout<<h<<”:”<<m<<”:”<<s; }
time(int i, int j, int k) {h=i; m=j; s=k;} int get_h() {return h;}};void main(){ const time noon(12,0,0); noon.print(); // cout<<noon.get_h(); //error since get_h
not const }
قصاص وائل 68
12:0:0
Friends (friend keyword) Friends (friend keyword)
There are three levels of internal protection for the different members of a class: public,
protected and private. In the case of members protected and
private, these could not be accessed from outside the same class at which they are declared. Nevertheless, this rule can be transgressed with the use of the friend keyword in a class, so we can allow an external function to gain access to the
protected and private members of a class.
قصاص وائل 69
Friend Functions Friend Functions
In order to allow an external function to have access to the private and
protected members of a class, declare the prototype of the external function that
will gain access by the keyword friend within the class declaration that shares its
members.
قصاص وائل 70
Example:Example:
class myclass {int a, b;
public:myclass(int i, int j) {a=i;b=j;}friend int sum(myclass x); };
// note: sum() is not a member function of any class
int sum(myclass x) {//sum() is a friend of myclass, it can access a and b
through object xreturn x.a+x.b;}
int main() { myclass n(3,4);
cout<<sum(n);return 0;}
قصاص وائل 71
#include <iostream.h>#include <iostream.h>class CRectangle { class CRectangle { int width, height; int width, height; public: public: void set_values (int, int); void set_values (int, int); int area (void) {return (width * height);} int area (void) {return (width * height);} friendfriend CRectangle duplicate (CRectangle); }; CRectangle duplicate (CRectangle); }; // End of Class def.// End of Class def. void CRectangle::set_values (int a, int b) { void CRectangle::set_values (int a, int b) { width = a; height = b; } width = a; height = b; }CRectangle duplicate (CRectangle R){ CRectangle duplicate (CRectangle R){ CRectangle T; CRectangle T; T.width = R.width*2; T.width = R.width*2; T.height = R.height*2; T.height = R.height*2; return (T); }return (T); }
void main () { void main () { CRectangle rect, rectb; CRectangle rect, rectb; rect.set_values (2,3); rect.set_values (2,3); rectb = duplicate (rect); rectb = duplicate (rect); cout << rectb.area(); } cout << rectb.area(); }
قصاص وائل 72
24
The use of friend functions is out of an OOP methodology, so it is preferable to use members of the same class to make the process.
As in the previous example, it would have been shorter to integrate duplicate() within the class CRectangle.
A function may be a friend of more than one class.
قصاص وائل 73
#include <iostream.h> const int IDLE =0;const int INUSE=1;class c2; //forward referenceclass c1 { int status; public:
void set_status(int state); friend int idle(c1 a, c2 b); };
class c2 { int status; public:
void set_status(int state); friend int idle(c1 a, c2 b); };
void c1::set_status(int state) { status=state; }
void c2::set_status(int state) { status=state; }
int idle(c1 a, c2 b) {if(a.status || b.status) return 0; else return 1; }
void main(){ c1 x; c2 y;
x.set_status(IDLE); y.set_status(IDLE);if ( idle(x,y) ) cout<<“screen can be used\n”;else cout << “Pop-up In use\n”;x.set_status(INUSE);if ( idle(x,y) ) cout <<“Screen can be used\n”;else cout <<“Pop-up in use\n”;}
قصاص وائل 74
Screen can be usedPop up in use
Friend Classes (friend) Friend Classes (friend)
we can define a class as friend of another one, allowing that the second one access to the protected and private members of the first one.
قصاص وائل 75
#include <iostream.h>class CSquare;class CRectangle { int width, height; public: int area (void) {return (width * height);} void convert (CSquare a); };
class CSquare { private: int side; public: void set_side (int a) {side=a;} friend class CRectangle; };
void CRectangle::convert (CSquare a) { width = a.side; height = a.side; }
void main () { CSquare sqr; CRectangle rect; sqr.set_side(4); rect.convert(sqr); cout << rect.area(); }
قصاص وائل 76
16
CRectangle is declared as a friend of CSquare so that CRectangle can access the protected and private members of CSquare, more concretely CSquare::side, that defines the square side width. In the first instruction of the program, the empty prototype of class CSquare is used. This is necessary because within the declaration of CRectangle, we refer to CSquare (as a parameter in convert()).
قصاص وائل 77
Topic covered up to nowTopic covered up to now
Function Overloading Struct: Classes: Public, private, scope operator (::) Empty constructor , Copy constructor Constructor Destructor New delete keywords and its relation with Constructor and
destructor Inline function Enum Arrays of objects and relation with pointers Static object Static function Const Object Const member function. Friend function Friend Class
قصاص وائل 78
Dynamic initialization Dynamic initialization In c++, both local and global variables can
initialized at run time. This process is sometimes referred to as Dynamic initialization.
Most initializations have used constants.Under Dynamic initialization, a variable can be
initialized at run time using any c++ expression valid at the time the variable is declared.
You can initialize a variable using other variables.The following are all perfectly valid variables
initializations in c++:int n = strlen(str);double arc = sin(theta);float d= 1.02 * count / deltax;
قصاص وائل 79
Applying Dynamic Initialization to Applying Dynamic Initialization to Constructors Constructors #include <iostream.h>class myclass {
int a, b;public:
void setab(int i, int j) {a=i; b=j;}void showab(); };
void myclass::showab() {cout << "a is " <<a << "\n";cout<< "b is " << b << "\n";}
main(){myclass obj1, obj2;obj1.setab(10, 20);obj2.setab(0,0);cout<<"obj1 before assignment:\n";obj1.showab();cout<< "obj2 before assignment: \n";obj2.showab();cout<< "\n";obj2=obj1;// assign ob1 to obj2cout<<"obj1 after assignment: \n";obj1.showab();cout<<"obj2 after assignment: \n";obj2.showab();}
قصاص وائل 80
obj1 befor assignment:a is 10b is 20
ob2 before assignment:a is 0b is 0
ob1 after assignment:a is 10b is 20
Ob2 after assignment:a is 10b is 20
Like simple variables, objects can be initialized dynamically when they are created.
This feature allows you to create exactly the type of object you need, using information that is known only at run time.
The point of overloading constructor functions is to help programmers handle greater complexity by allowing objects to be constructed in the most natural manner relative to be used.
Assigning Objects: you can assign object to another if both objects of the same type (both are of the same class).
It is not sufficient for the two classes to simply be physically similar-their type names must be the same.
When one object is assigned to another, the first object data is copied to the second.
قصاص وائل 81
#include <iostream.h>class C1{ int x,y;public:
C1(){}C1(int a,int b){x=a;y=b;}}; //End of Class C1
class C2{ int x,y;public:
C2(){}C2(int a,int b){x=a,y=b;} }; //End of Class C2
void main(){ C1 L,M(10,20);
C2 N,P;L=M;N=P;N=M; //Error no acceptable conversion } //End of main
قصاص وائل 82
Passing Objects to Functions Passing Objects to Functions
An object can be passed to a function in the same way as any other data type.
Objects are passed to functions using the normal c++ call-by-value parameter passing convention. This means that a copy of the object, not the actual object itself, is passed to the function.
Any change made to the object inside the function does not affect the object used as argument to the function.
قصاص وائل 83
#include <iostream.h>class OBJ {
int i;public:
void set_i(int x) { i = x;}void out_i() {cout << i << " ";}};
void f(OBJ x) {x.out_i(); // outputs 10;x.set_i(100); // this affects only local copy x.out_i();} // outputs 100;
void main(){ OBJ o;
o.set_i(10);f(o);o.out_i(); // still outputs 10, value of I unchanged}
قصاص وائل 84
10 100 10
The Modification of x within f() has no effect on object o inside main()
Constructors, Destructors, and Passing ObjectsConstructors, Destructors, and Passing Objects
#include <iostream.h>class myclass {
int val;public:
myclass(int i) { val=i; cout<<“Constructing\n”;}
~myclass() {cout <<“Destructing\n”;} int getval() { return val;}};
void display(myclass ob) {cout<<ob.getval()<<“\n”;}
void main() { myclass a(10);
display (a);}
Constructing 10
DestructingDestructing
Passing simple objects as arguments to functions is a straightforward procedure.
As you can see, there is one call to the constructor function (as expected), but there are two calls to the destructor. Why?
When an object is passed to a function, a copy of that object is made (and this copy becomes the parameter in the function). This means that a new object comes into existence. Also, when the function terminates, the copy of the argument (i.e., the parameter) is destroyed.
This raises two questions: first, is the object’s constructor called when the copy is made? Second, is the object’s destructor called when the copy is destroyed?
قصاص وائل 86
When a copy of an argument is made during a function call, the constructor function is not called. because the constructor function is generally used to initialize some aspect of an object, it must not be called to make a copy of an already existing object that is being passed to a function. When passing an object to a function, you want to use the current state of the object, not its initial state.
When the function terminates and the copy is destroyed, the destructor function is called. This is because the object might perform some operations that must be undone when it goes out of scope. For example the copy may allocate memory that must be released.
Finally when a copy of an object is created to be used as an argument to a function, the constructor function is not called.
When the copy is destroyed (usually by going out of scope when the function returns), the destructor function is called.
A potential problem when passing A potential problem when passing objectsobjects
If an object used as an argument allocates dynamic memory and frees that memory when it is destroyed, then its local copy inside the function will free the same memory when its destructor is called. This will leave the original object damaged and effectively useless so the abort screen will appear.
قصاص وائل 88
#include <iostream.h>#include <stdlib.h>class myclass {
int *p;public:
myclass(int i);~myclass();int getval(){return *p;}};
myclass::myclass(int i) {cout<<"allocating p\n";p=new int; if (p==NULL) {
cout<<"allocating failure"; exit(1);} //exit program if out of memory
*p=i;}myclass::~myclass() {
cout<<"Freeing p\n";delete p;}
//This will cause a problem.void display(myclass ob) { // try to use &ob what will happen??
cout<<ob.getval()<<"\n"; }void main(){ myclass a(10); display(a);}
قصاص وائل 89
Abort screen
ThisThis
Each time a member function is invoked, it is automatically passed a pointer, called this, to the object that has invoked. The "this" pointer is an implicit parameter to all member functions. Therefore, inside a member function, this may be used to refer to the invoking object. For the following example:
class c1 {int i; void load_i(int val){i=val;)};
i=val; statement can be used in a member function (load_i ) to assign i the value of val. In actuality, the preceding statement is shorthand for: this->i=10;
قصاص وائل 90
#include <iostream.h>class c1 {
int i;public:
void load_i(int val) {this->i=val;} // same as i=valint get_i() {return this->i;} // same as return i
};int main(){ c1 o;
o.load_i(100);cout<<o.get_i();return 0;}
قصاص وائل 91
100
Operator OverloadingOperator Overloading
C++ incorporates the option to use language standard operators between classes and between fundamental types. For example:
int a, b, c; a = b + c;is valid, since the different variables of the
addition are all fundamental types. While, the following operation is incorrect.
struct { char product [50]; float price; } a, b, c;a = b + c;
قصاص وائل 92
The assignation of a class (or struct) to another one of the same type is allowed (default copy constructor). But addition operation in principle is not valid between non-fundamental types.
C++ has the ability to overload operators. Objects derived from composed types such as the previous one can accept operators which would not be accepted otherwise, and we can even modify the effect of operators. Here is a list of all the operators that can be overloaded:
+ - * / = < > += -= *= /= << >>
<<= >>= == != <= >= ++ -- % & ^ ! |
~ &= ^= |= && || %= [] () new delete
To overload an operator we only need to write a class member function whose name is operator followed by the operator sign that we want to overload, following this prototype:
type operator sign (parameters);
Here you have an example that includes the operator +. We are going to sum the bi-dimensional vectors a(3,1) and b(1,2). The addition of two bi-dimensional vectors is an operation as simple as adding the two x coordinates to obtain the resulting x coordinate and adding the two y coordinates to obtain the resulting y. In this case the result will be (3+1,1+2) = (4,3).
#include <iostream.h>class CVector { public: int x,y; CVector () { }; CVector (int,int); CVector operator + (CVector); };CVector::CVector (int a, int b) { x = a; y = b;}CVector CVector::operator+ (CVector param) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp);}
void main () { CVector a (3,1); CVector b (1,2); CVector c; c = a + b; cout << c.x << "," << c.y;}
قصاص وائل 95
4,3
The function operator+ of class CVector is the one that is in charge of overloading the arithmetic operator +. This one can be called by any of these two ways:
c = a + b; c = a.operator+ (b);
Notice also that we have included the empty constructor (without parameters) and defined it with a no-op block of instructions: CVector () { };this is necessary, since there already exists another constructor, CVector (int, int);so none of the default constructors will exist in CVector if we do not explicitly declare one as we have done. Otherwise the declaration CVector c; included in main() would not be valid. Therefore, a more advisable declaration would have been something similar to this: CVector () { x=0; y=0; };
As well as a class includes by default an empty and a copy constructor, it also includes a default definition for the assignation operator (=) between two classes of the same type. This copies the whole content of the non-static data members of the parameter object (the one at the right side of the sign) to the one at the left side. Of course, you can redefine it to any other functionality that you want for this operator, like for example, copy only certain class members.
Although the prototype of a function operator+ can seem obvious since it takes the right side of the operator as the parameter for the function operator+ of the left side object, other operators are not so clear. Here you have a table with a summary on how the different operator functions must be declared (replace @ by the operator in each case):
where a is an object of class A, b is an object of class B and c is an object of class C.
You can see in this panel that there are two ways to overload some
class operators: as member function and as global function. Its use is
indistinct; considering that functions that are not members of a class
cannot access the private or protected members of the class unless
the global function is friend of the class.
Operator Overloading Using Member Functions Operator Overloading Using Member Functions class myClass {
int x, y, z;public:
myClass() {x=y=z=0;}myClass(int i, int j, int k){x=i; y=j; z=k;}myClass operator+(myClass t);myClass operator=(myClass t);void show();};
myClass myClass::operator+(myClass t) {myClass temp;temp.x=x+t.x;temp.y=y+t.y;temp.z=z+t.z;return temp; }
myClass myClass::operator=(myClass t) {
x=t.x;y=t.y;z=t.z;return *this;}
void myClass::show() {cout<<x<<“, “;cout<<y<<“, “;cout<<z<<“\n “; }
void main() {myClass a(1,2,3), b(10,10,10), c;a.show();b.show();c=a+b;c.show();c=a+b+c;c.show();c=b=a;c.show();b.show(); }
The Output is:1,2,310,10,1011,12,1322,24,261,2,31,2,3
when a binary operator is overloaded using a member function, only one argument is explicitly passed to it. The other argument is implicitly passed using "this" pointer. Thus, in the line
temp.x=x+t.x;
The x refers to this->x, which is the x associated with the object that invokes the operator function. In all cases it is the object on the left side of an operation that causes the call to the operator function. The object on the right side is passed to the function.
when you use a member function, no parameters are used when overloading a unary operator and only one parameter is required when overloading a binary operator.
Operator+() returns an object of type myClass. Although the function could have returned any valid C++ type, the fact that it returns a myClass object allows the + operator to be used in compound expressions, such as a+b+c. Here, a+b generates a result that is of type myClass. This value can then be added to c.
The operator=() function is called by the object that occurs on the left side of the assignment, it is this object that is modified by the assignment operation.
The return value of an overloaded assignment operator is the object on the left, after the assignment has been made.
Using Member Functions to Overload Unary OperatorsUsing Member Functions to Overload Unary Operators
When a unary operator (i.e. ++ , --) is overloaded by means of
a member function, no object is explicitly passed to the
operator function. Instead, the operation is performed on the
object that generates the call to the function through the
implicitly passed this pointer.
#include <iostream.h>#include <stdlib.h>class myClass {
int x, y, z;public:
myClass() {x=y=z=0;}myClass(int i, int j, int k){x=i; y=j; z=k;}myClass operator+(myClass t);myClass operator++();void show();};
myClass myClass::operator++(){ ++x;
++y;++z;return *this;}
myClass myClass::operator+(myClass t) {myClass temp;temp.x=x+t.x;temp.y=y+t.y;temp.z=z+t.z;return temp;}
void myClass::show() {cout<<x<<", ";cout<<y<<", ";cout<<z<<"\n ";}
void main() {myClass a(1,2,3), b(10,10,10), c;a.show(); b.show();c=a+b; c.show();c=a+b+c; c.show();c=b=a; c.show();b.show();++c; c.show();}
قصاص وائل 104
1, 2, 3 10, 10, 10 11, 12, 13 22, 24, 26 1, 2, 3 1, 2, 3 2, 3, 4
operator++() increments each coordinate in the object and returns the modified object.
The ++ and -- have both a prefix and a postfix form. In the preceding program, the operator++() function defines the prefix form of ++ relative to the three_d class.
It is possible to overload the postfix form. The post operator will call the parameterized function, while the
prefix will always call the non-parameterized function. The prototype for the postfix form of the ++ operator relative to the
three_d class is shown here: three_d three_d::operator++(int notused); The parameter not used is not used by the function, and should be
ignored. This parameter is simply a way for the compiler to distinguish between the prefix and postfix forms of the increment and decrement operators.
class three_d {int x, y, z;
public: three_d() {x=y=z=0;} three_d(int i, int j, int k){x=i; y=j; z=k;} three_d operator+(three_d op2); three_d operator=(three_d op2); three_d operator++(); three_d operator++(int notused); // postfix void show(); };
three_d three_d::operator+(three_d op2){ three_d temp;
temp.x=x+op2.x;temp.y=y+op2.y;temp.z=z+op2.z;return temp; }
three_d three_d::operator=(three_d op2){ x=op2.x;
y=op2.y;z=op2.z;return *this;}
three_d three_d::operator++(){ ++x; ++y; ++z;
return *this;}three_d three_d::operator++(int notused){ three_d temp=*this;
x++; y++; z++;return temp;}
void three_d::show() {cout<<x<<", ";cout<<y<<", ";cout<<z<<"\n ";}
void main(){ three_d a(1,2,3), b(10,10,10), c;a.show(); b.show(); c=a+b; c.show();c=a+b+c; c.show(); c=b=a; c.show(); b.show(); ++c; c.show();c++; c.show(); a=++c; a.show(); c.show();a=c++; a.show(); c.show(); }
1, 2, 3 10, 10, 10 11, 12, 13 22, 24, 26
1, 2, 3 1, 2, 3 2, 3, 4 3, 4, 5 4, 5, 6 4, 5, 6 4, 5, 6 5, 6, 7
Overloading a relational operator Overloading a relational operator
such as == or <, is a straightforward process.
overloaded operator function usually returns an object of the class for which it is overloaded. However, an overloaded relational operator typically returns a true or false value.
To show how an overloaded relational operator can be implemented, the following function overloads the "==".
int three_d::operator==(three_d t) {if ((x==t.x) && (y==t.y) && (z==t.z))
return 1;else
return 0;}
class RelationalOver {int x, y, z;
public: RelationalOver() {x=y=z=0;} RelationalOver(int i, int j, int k){x=i; y=j; z=k;} int operator==(RelationalOver op2); };
int RelationalOver::operator==(RelationalOver t) {if ((x==t.x) && (y==t.y) && (z==t.z))
return 1;else
return 0;}
void main(){ RelationalOver a(10,10,10), b(10,10,10);if (a==b) cout<<"The two objects are equal";elsecout<<"The two objects are not equal";}
Friend Operator FunctionsFriend Operator Functions
The only operators that cannot be overloaded using friend functions are =,(),and ->.
Friend functions do not have a this pointer.When a friend is used to overload an operator, both
operands are passed explicitly if a binary operator is overloaded. If a unary operator is overloaded then a single operand is passed.
In The next program, a friend is used instead of a member function to overload the + operation.
قصاص وائل 109
Friend Operator Friend Operator FunctionsFunctions
There is one situation in which you must use a friend function.
A pointer to the object that invokes a member operator function is passed in this. In the case of a binary operator, the object on the left invokes the function. This is fine, provided that the object on the left defines the specified operation. Assuming some object called O, which has assignment and addition defined for it, then this is perfectly valid statement:
O = O + 10; //will workWhile;
O = 10 + O; //won’t work The problem with the above statement is that the object
on the left side of the + operator is an integer, a built-in type for which no operation involving an integer and an object of O’s type is defined.
Solution: The problem of having a built-in type on the left side of
an operation can be eliminated if the + is overloaded using two friend functions. In this case, the operator function is explicitly passed both arguments, and it is invoked like any other overloaded function, based upon the types of its argument.
class CL {public:
int count;CL operator=(CL obj);friend CL operator+(CL ob, int i);friend CL operator+(int i, CL ob);
};CL CL::operator=(CL obj) {
count = obj.count;return *this;
}//this handles ob + int.CL operator+(CL ob, int i){
CL temp;temp.count=ob.count+i;return temp;
}
//this handles int + ob.CL operator+(int i, CL ob){
CL temp;temp.count=ob.count+i;return temp;
}main() {
CL o;o.count=10;cout<<o.count<<“ “;//outputs 10o=10+ o;// adds object to integer.cout<<o.count<<“ “;//outputs 20o=o+12;// adds integer to object.cout<<o.count; // outputs 32return o;
}قصاص وائل 111
Using a Friend to Overload a Unary Using a Friend to Overload a Unary OperatorOperator
In overloaded unary operator using member function, Every member function has an implicit argument, a pointer to the object that invokes it, which is referenced inside the member function by the keyword this.
Unlike member functions, a friend function does not receive a this pointer. And therefore cannot reference the object that invoked it. Instead, a friend operator function is passed its operand explicitly. For this reason, trying to create a friend operator++() function as shown here will not work.
//This will not workthree_d operator++(three_d op1){
op1.x++; op1.y++; op1.z++; return op1;}
قصاص وائل 112
This function will not work because only a copy of the object that activated the call to operator++() is passed to the function in parameter op1. Thus, the changes inside will not effect the calling object
Using a friend function when overloading a unary ++ or -- requires that the object be passed to the function as a reference parameterreference parameter. In this way the function can modify the object.
When a friend is used for overloading the increment or decrement operators, the prefix form takes one parameter. The postfix form takes two parameters. The second is an integer, which is not used.
قصاص وائل 113
class three_d {int x, y, z;
public:three_d() {x=y=z=0;}three_d(int i, int j, int k){x=i; y=j; z=k;}friend three_d operator+(three_d op1, three_d op2);three_d operator=(three_d op2);friend three_d operator++(three_d &op1); // prefix friend three_d operator++(three_d &op1 , int notused); void show();
};
three_d operator+(three_d op1 , three_d op2){
three_d temp;temp.x=op1.x+op2.x;temp.y=op1.y+op2.y;temp.z=op1.z+op2.z;return temp; }
قصاص وائل 114
three_d three_d::operator=(three_d op2)
{x=op2.x;y=op2.y;z=op2.z;return *this;
}
three_d operator++(three_d &op1){
op1.x++;op1.y++;op1.z++;return op1;
}
//overload the postfix version three_d operator++(three_d &op1,
int notused)
{three_d temp=op1;op1.x++;op1.y++;op1.z++;return temp;
}
void three_d::show() {cout<<x<<“, “;cout<<y<<“, “;cout<<z<<“\n “;
}
main(){three_d a(1,2,3), b(10,10,10),
c;a.show();b.show();c=a+b; c.show();c=a+b+c; c.show();c=b=a;c.show(); b.show();++c; // prefix incrementc.show();c++;//postfix incrementc.show();a=++c;
a.show();c.show();a=c++;a.show();c.show();return 0;}
قصاص وائل 116
Overloading [ ]Overloading [ ]
The last operator we will overload is the [] array subscripting operator. In C++, the [] is considered a binary operator when it is overloaded.
The [] can only be overloaded relative to a class, and only by a member function. Therefore, the general form of a member operator[ ]() function is:
type class-name::operator[](int index){
// ……}
Technically, the parameter does not have to be of type int, but operator[]() functions are typically used to provide array subscripting, so an integer value is generally used.
قصاص وائل 117
Given an object called O, this expression
O[3]
Translates into this call to the operator[]() function: operator[](3)
That is, the value of the expression within the subscripting operator is passed to the operator[]() function explicitly.
The this pointer will point to O, the object that generated the call. In the following program , atype declares an array of three integers.
Its constructor function initialize each member of the array. The overloaded operator[]() function returns the value of the element specified by its parameter.
قصاص وائل 118
#include <iostream>using namespace std;const int SIZE=3;class atype {int a[SIZE];
public:atype() {register int i;for(i=0; i<SIZE;i++) a[i] = i;}int operator[](int i) {return i;}
};int main(){atype ob;cout<<ob[2]; // display 2return 0;
}
قصاص وائل 119
In the previous slide, the initialization of the array a by the constructor. It is possible to design the operator[]() function in such a way that the [] can
be used on both the left and right sides of an assignment statement. To do this, simply specify that the return value of operator[]() be a reference.
const int SIZE=3;class atype {
int a[SIZE];public:
atype() {register int i;for(i=0; i<SIZE;i++) a[i] = i; }
int &operator[](int i) {return a[i];}};void main(){
atype ob;cout<<ob[2]; // display 2cout<<“ “; ob[2]=25; // [] on left of =cout<<ob[2]; // now display 25
}
(in the previous program) Because operator[]() now returns a reference to the array element indexed by i, it can now be used on the left side of an assignment statement to modify an element of the array.
One advantage of being able to overload the [] operator is that it provides a means of implementing safe array indexing. As you know, in C++, it is possible to overrun an array boundary at run time without generating a run-time error message. However, if you create a class that contains the array, and allow access to that array only through the overloaded [] subscripting operator, then you can intercept an out-of-range index. For example, the program shown next adds a range check to the preceding program, and proves that it works.
قصاص وائل 121
#include <iostream.h>#include <stdlib.h>const int SIZE=3;class atype {
int a[SIZE];public:
atype() {register int i;for(i=0; i<SIZE;i++) a[i] = i;
}int &operator[](int i);
};// provide range checking for atypeint &atype::operator[](int i) {
if(i<0 || i>SIZE-1) {cout<<“\nindex value of “;cout<<i<<“ is out-of-range.\
n”;exit(1);
}return a[i];}
main(){
atype ob;cout<<ob[2]; // display 2cout<<“ “; ob[2]=25; // [] on left of =cout<<ob[2]; // display 25ob[3] = 44; // generates //runtime error, 3 //out=of-rangereturn 0;
}In this program, when the
statement ob[3]=44; executes, the boundary error is intercepted by operator[](), and the program is terminated befor any damage can be done.
قصاص وائل 122
Inheritance Inheritance
In order to derive a class from another, we must use the operator: (colon) in the declaration of the derived class in the following way:
class derived_class_name: public base_class_name;where derived_class_name is the name of the derived class
and base_class_name is the name of the class on which it is based. public may be replaced by any of the other access specifiers protected or private, and describes the access for the inherited members
قصاص وائل 123
#include <iostream.h>class CPolygon { protected: int width, height; public: void set_values (int a, int b){ width=a; height=b;} };
class CRectangle: public CPolygon { public: int area (void) { return (width * height); } };
class CTriangle: public CPolygon { public: int area (void) { return (width * height / 2); } };
void main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); cout << rect.area() << endl; cout << trgl.area() << endl; }
قصاص وائل 124
2010
Objects of classes CRectangle and CTriangle each contain members of CPolygon, that are: width, height and set_values(). The protected specifier is similar to private, its only difference occurs when deriving classes. When we derive a class, protected members of the base class can be used by other members of the derived class. Nevertheless, private member cannot. Since we wanted width and height to have the ability to be manipulated by members of the derived classes CRectangle and CTriangle and not only by members of CPolygon, we have used protected access instead of private.
قصاص وائل 125
We can summarize the different access types according to whom can access them in the following way:
Access Public protected private
members of the same class
yes yes yes
members of derived classes
yes yes no
not-members yes no no
قصاص وائل
126
where "not-members" represent any reference from outside the class, such as from main(), from another class or from any function, either global or local. In above example, the members inherited by CRectangle and CTriangle follow with the same access permission as in the base class CPolygon:
CPolygon::width // protected accessCRectangle::width // protected accessCPolygon::set_values() // public accessCRectangle::set_values() // public access This is because we have derived a class from the other as public,
remember: class CRectangle: public CPolygon;
This public keyword represents the minimum level of protection that the inherited members of the base class (CPolygon) must acquire in the new class (CRectangle). The minimum access level for the inherited members can be changed by specifying protected or private instead of public. For example, daughter is a class derived from mother that we defined thus:
class daughter: protected mother; This would establish protected as the minimum access level for the
members of daughter that it inherited from mother. That is, all members that were public in mother would become protected in daughter, that would be the minimum level at which they can be inherited. Of course, this would not restrict that daughter could have its own public members. The minimum level would only be established for the inherited members of mother.
The most common use of an inheritance level different from public is private that serves to completely encapsulate the base class, since, in that case, nobody except its own class will be able to access the members of the base class from which it is derived. Anyway, in most cases classes are derived as public. If no access level is explicitly written, private is assumed for classes created with the class keyword and public for those created with struct.
Granting Access: When a base class is inherited as private, all members of that class (public or protected) become private members of the derived class. However, in certain circumstances, you may want to restore one or more inherited members to their original access specification. For example, you might want to grant certain public members of the base class public status in the derived class even though the base class is inherited as private. To do this, you must use an access declaration within the derived class. An access declaration takes this general form:
base-class::member;
قصاص وائل 130
class base {public:
int j; // public in base};
// Inherit base as privateclass derived: private base {public:
base::j; // make j public again// …….
};
You can use an access declaration to restore the access rights of public and protected members. However, you cannot use an access declaration to raise or lower a member’s access status. For example, a member declared as private within a base class cannot be made public by a derived class. (allowing this would destroy encapsulation!).
class base { int i; // private to base public: int j, k; void seti(int x) {i=x;} int geti() {return i;}};
class derived: private base { /* The next three statements override
base’s inheritance as private and restore j, seti() and geti() to public access. */
public: base::j; // make j public again base::seti; // make seti() public base::geti; // make geti() public
// base::i; //illegal, you cannot elevate
access int a; }; // public
قصاص وائل 132
void main(){ derived ob;//ob.i=10; illegal because ob.j=20; /* legal j is made public*///ob.k=30;/*illegal k is private */ob.a=40;/* legal a is public*/ ob.seti(10); cout<<ob.geti()<<“ “; cout<<ob.j<<“ “<<ob.a;}
What is inherited from the base class? What is inherited from the base class?
In principle every member of a base class is inherited by a derived class except:
Constructor and destructor operator=() member friends Although the constructor and destructor of the base class are not inherited,
the default constructor (i.e. constructor with no parameters) and the destructor of the base class are always called when a new object of a derived class is created or destroyed.
If the base class has no default constructor or you want that an overloaded constructor is called when a new derived object is created, you can specify it in each constructor definition of the derived class:
derived_class_name (parameters): base_class_name (parameters) {}
قصاص وائل 134
// constructors and derivated classes#include <iostream.h>class mother { public: mother () { cout << "mother: no parameters\n"; } mother (int a) { cout << "mother: int parameter\n"; } };
class daughter : public mother { public: daughter (int a) { cout << "daughter: int parameter\n\n"; } };
class son : public mother { public: son (int a) : mother (a) { cout << "son: int parameter\n\n"; } };
void main () { daughter cynthia (1); son daniel(1);}
mother: no parametersdaughter: int parameter mother: int parameterson: int parameter
Observe the difference between which mother's constructor is called when a new daughter object is created and which when it is a son object. The difference is because the constructor declaration of daughter and son:
daughter (int a) // nothing specified: call default constructor
son (int a) : mother (a) // constructor specified: call this one
قصاص وائل 135
Multiple inheritance Multiple inheritance
In C++ it is perfectly possible that a class inherits fields and methods from more than one class simply by separating the different base classes with commas in the declaration of the derived class. For example, if we had a specific class to print on screen (COutput) and we wanted that our classes CRectangle and CTriangle also inherit its members in addition to those of CPolygon we could write:
class CRectangle: public CPolygon, public COutput {}class CTriangle: public CPolygon, public COutput { }
قصاص وائل 136
#include <iostream.h>
class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a;
height=b;}};
class COutput { public: void output (int i); };
void COutput::output (int i){ cout << i << endl; }
class CRectangle: public CPolygon, public COutput { public: int area (void) { return (width * height); } };
class CTriangle: public CPolygon, public COutput { public: int area (void) { return (width * height / 2); }};
قصاص وائل 137
void main () { CRectangle rect; CTriangle trgl; rect.set_values (4,5); trgl.set_values (4,5); rect.output (rect.area()); Trgl.output (trgl.area());}
2010
Polymorphism Polymorphism
For a suitable understanding of this section you should clearly know how to use pointers and inheritance between classes.
Polymorphism in the context of object-oriented programming, is the ability of one type, A, to appear as and be used like another type, B. Type A somehow derives from type B, or type C implements an interface that represents type B.
قصاص وائل 138
Pointers to base class Pointers to base class
One of the greater advantages of deriving classes is that a pointer to a derived class is type-compatible with a pointer to its base class.
قصاص وائل 139
// pointers to base class#include <iostream.h>
class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } };
class CRectangle: public CPolygon { public: int area (void){ return (width * height); } };
class CTriangle: public CPolygon { public: int area (void){ return (width * height / 2); } };
قصاص وائل 140
int main () { CRectangle rect; CTriangle trgl;
CPolygon * p1 = ▭ CPolygon * p2 = &trgl;
p1->set_values (4,5); p2->set_values (4,5);
cout << rect.area() << endl; cout << trgl.area() << endl; return 0;}
2010
Code
The function main creates two pointers that point to objects of class CPolygon, that are *p1 and *p2. These are assigned to the addresses of rect and trgl, and because they are objects of classes derived from CPolygon they are valid assignations.
The only limitation of using *p1 and *p2 instead of rect and trgl is that both *p1 and *p2 are of type CPolygon* and therefore we can only refer to the members that CRectangle and CTriangle inherit from CPolygon. For that reason when calling the area() members we have not been able to use the pointers *p1 and *p2.
To make it possible for the pointers to class CPolygon to admit area () as a valid member, this should also have been declared in the base class and not only in its derived ones.
Virtual members Virtual members
In order to declare an element of a class which we are going to redefine in derived classes we must precede it with the keyword virtual so that the use of pointers to objects of that class can be suitable.
قصاص وائل 142
#include <iostream.h>class CPolygon { protected: int width, height; public: void set_values (int a, int b)
{ width=a; height=b; } virtual int area (void) { return (0); } };
class CRectangle: public CPolygon { public: int area (void){ return (width * height); } };
class CTriangle: public CPolygon { public:
int area (void){ return (width * height /
2); } };
int main () { CRectangle rect; CTriangle trgl; CPolygon poly; CPolygon * p1 = ▭CPolygon *p2=&trgl;CPolygon * p3 = &poly;p1->set_values(4,5);p2->set_values(4,5);p3->set_values (4,5); cout << p1->area() << endl; cout << p2->area() << endl; cout << p3->area() << endl;}
قصاص وائل 143
20100
The three classes (CPolygon, CRectangle and CTriangle) have the same members: width, height, set_values() and area(). area() has been defined as virtual because it is later redefined in derived classes. You can verify if you want that if you remove this word (virtual) from the code and then you execute the program the result will be 0 for the three polygons instead of 20,10,0. That is because instead of calling the corresponding area() function for each object (CRectangle::area(), CTriangle::area() and CPolygon::area(), respectively), CPolygon::area() will be called for all of them since the calls are via a pointer to CPolygon. Therefore, what the word virtual does is to allow a member of a derived class with the same name as one in the base class be suitably called when a pointer to it is used
Note that in spite of its virtuality we have also been able to declare an object of type CPolygon and to call its area() function, that always returns 0 as the result.
Abstract base classes Abstract base classes Abstract classes are similar to the class CPolygon of our previous example.
The only difference is that in our previous example we have defined a valid area() function for objects that were of class CPolygon (like object poly), whereas in an abstract base class we could have simply left without defining this function by appending = 0 to the function declaration.
The class CPolygon could have been thus:
// abstract class CPolygonclass CPolygon { protected: int width, height; public: void set_values(int a, int b){width=a; height=b;} virtual int area (void) =0; };
This type of function is called a pure virtual function, and all classes that contain a pure virtual function are considered abstract base classes.
The greatest difference of an abstract base class is that instances (objects) of it cannot be created, but we can create pointers to them. Therefore a declaration likes:
CPolygon poly; // incorrectCPolygon * ppoly1; //correct
This is because the pure virtual function that it includes is not defined and it is impossible to create an object if it does not have all its members defined. A pointer that points to an object of a derived class where this function has been defined is perfectly valid.
#include <iostream.h>class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a;
height=b; } virtual int area (void) =0; };
class CRectangle: public CPolygon { public: int area (void){ return (width * height); } };
class CTriangle: public CPolygon { public: int area (void){ return (width * height / 2); } };
int main () { CRectangle rect; CTriangle trgl; CPolygon * ppoly1 = ▭ CPolygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << ppoly1->area() << endl; cout << ppoly2->area() << endl;
return 0;}
2010
If you review the program you will notice that we can refer to objects of different classes using a unique type of pointer (CPolygon*). This can be tremendously useful. Imagine, now we can create a function member of CPolygon that is able to print on screen the result of the area() function independently of what the derived classes are.
قصاص وائل 148
#include <iostream.h>class Polygon { protected: int width, height; public: void set_values (int a, int b){ width=a; height=b; } virtual int area (void) =0; void printarea (void){ cout << this->area() << endl; } };
class Rectangle: public Polygon { public: int area (void){ return (width * height); } };
class Triangle: public Polygon { public: int area (void){ return (width * height / 2); } };
int main () { Rectangle rect; Triangle trgl; Polygon * p1 = ▭ Polygon * p2 = &trgl; p1->set_values (4,5); p2->set_values (4,5); p1->printarea(); p2->printarea(); return 0;}
قصاص وائل 149
Remember that this represents a pointer to the object whose code is being executed.
Abstract classes and virtual members grant to C++ the polymorphic characteristics that make object-oriented programming such a useful instrument. Of course we have seen the simplest way to use these features, but imagine these features applied to arrays of objects or objects assigned through dynamic memory.
قصاص وائل 150
Early Versus Late BindingEarly Versus Late BindingEarly binding and late binding. These terms refer to
events that occur at compile time and events that occur at run time.
Early binding means that a function call is resolved at compile time. All information necessary for determining which function will be called is known when the program is compiled. (i.e. standard function calls, overloaded function calls, and overloaded operator function calls). The principle advantage to early binding is efficiency-it is faster, and it often requires less memory. Its disadvantage is lack of flexibility.
قصاص وائل 151
Late binding means that a function call is resolved at run time. Thus, precisely when function will be called is determined “on the fly” as the program executes. Late binding is a achieved in C++ through the use of virtual functions and derived types. The advantage to late binding is that it allows greater flexibility.
It can be used to support a common interface, while allowing various objects that utilize that interface to define their implementations.
Help in create class libraries, which can be reused and extended. Its disadvantage, however, is a slight loss of execution speed.
Most large programs use a combination of both. Late binding is one of the most powerful features of C++. However, the price you pay for this power is that your program will run slightly slower. Therefore, it is best to use late binding only when it meaningfully adds to the structure and manageability of your program. Keep in mind, however, that the loss of performance caused by late binding is very slight so when the situation calls for late binding, you should most definitely use it.
قصاص وائل 153
Function templates Function templates Templates allow creating generic functions that accept any data type as
parameters and return a value without having to overload the function with all the possible data types. Its prototype is any of the two following ones:
template <class identifier> function_declaration; template <typename identifier> function_declaration;
The difference between both prototypes is the use of keyword class or typename, its use is indistinct since both expressions have exactly the same meaning and behave exactly the same way.
For example:template <class GenericType>GenericType GetMax(GenericType a, GenericType b){ return (a>b?a:b); }
We have called GenericType. Therefore in the function that follows, GenericType becomes a valid data type and it is used as the type for its two parameters a and b and as the return type for the function GetMax. GenericType still does not represent any concrete data type; when the function GetMax will be called we will be able to call it with any valid data type. This data type will serve as a pattern and will replace GenericType in the function. The call to a template class is as follows:
function <pattern> (parameters); int x,y; GetMax <int> (x,y);
GetMax will be called as if each appearance of GenericType was replaced by an int expression.
#include <iostream.h>template <class T>T GetMax (T a, T b) { T result; result = (a>b)? a : b; return (result); }
void main () { int i=5, j=6, k; long l=10, m=5, n; k=GetMax<int>(i,j); n=GetMax<long>(l,m); cout << k << endl; cout << n << endl; }
قصاص وائل 156
610
We have written a function template and called it with two different patterns. In concrete case where the generic T type is used as a parameter for function GetMax, the compiler can find out automatically which data type is passed to it without having to specify it with patterns <int> or <long>. So we could have written:
int i,j; GetMax (i,j); i and j are of type int the compiler would assume
automatically that the type is int. This implicit method is more usual and would produce the same result:
// function template II#include <iostream.h>template <class T>T GetMax (T a, T b) { return (a>b?a:b); }
int main () { int i=5, j=6, k; long l=10, m=5, n; k=GetMax(i,j); n=GetMax(l,m); cout << k << endl; cout << n << endl; return 0;}
قصاص وائل 158
610
Because our template function includes only one data type (class T) and both arguments it admits are both of that same type, we cannot call our template function with two objects of different types as parameters:
int i; long l; k = GetMax (i,l);
This would be incorrect, since our function waits for two arguments of the same type (or class). We can also make template-functions that admit more than one generic class or data type. For example:
template <class T, class U>T GetMin (T a, U b) {return (a<b?a:b); }
In the previous case, our template function GetMin() admits two parameters of different types and returns an object of the same type as the first parameter (T) that is passed. For example, after that declaration we could call the function by writing:
int i,j;long l;i = GetMin<int,long> (j,l);
or simply i = GetMin (j,l);
Class templates Class templates
In class templates, so that a class can have members based on generic types that do not need to be defined at the moment of creating the class or whose members use these generic types. For example:
template <class T> class pair { T values [2]; public: pair (T first, T second) { values[0]=first; values[1]=second; }};
Class to store two elements of any valid type. pair<int> myobject (115, 36); pair<float> myfloats (3.0, 2.18);
The only member function has been defined inline within the class declaration. If we define a function member outside the declaration we must always precede the definition with the prefix template <... >.
قصاص وائل 162
#include <iostream.h>template <class T> class pair { T value1, value2; public: pair (T first, T second) {value1=first; value2=second;} T getmax (); };
template <class T>T pair<T>::getmax () { T retval; retval = value1>value2? value1 :
value2; return retval; }
قصاص وائل 163
100
int main () { pair <int> myobject (100, 75); cout << myobject.getmax(); return 0;}
notice how the definition of member function getmax begins:
template <class T>T pair<T>::getmax ()
All Ts that appear are necessary because whenever you declare member functions you have to follow a format similar to this (the second T makes reference to the type returned by the function, so this may vary).
قصاص وائل 164
Template specialization Template specialization
A template specialization allows a template to make specific implementations when the pattern is of a determined type. For example, suppose that our class template pair included a function to return the result of the module operation between the objects contained in it, but we only want it to work when the contained type is int. For the rest of the types we want this function to return 0. This can be done the following way:
قصاص وائل 165
#include <iostream.h>template <class T>class pair { T value1, value2; public: pair (T first, T second) {value1=first; value2=second;} T module () {return 0;}};
template < > class pair <int> { int value1, value2; public: pair (int first, int second) {value1=first; value2=second;} int module ();};
template < >int pair<int>::module() { return value1%value2; }
قصاص وائل 166
250
int main () { pair <int> myints (100,75); pair <float> myfloats (100.0,75.0); cout << myints.module() << '\n'; cout << myfloats.module() << '\n'; return 0;}
As you can see in the code the specialization is defined this way: template < > class class_name <type> The specialization is part of a template, for that reason we must
begin the declaration with template < >. And indeed because it is a specialization for a concrete type, the generic type cannot be used in it and the first angle-brackets < > must appear empty. After the class name we must include the type that is being specialized enclosed between angle-brackets < >.
When we specialize a type of a template we must also define all the members equating them to the specialization (if one pays attention, in the example above we have had to include its own constructor, although it is identical to the one in the generic template). The reason is that no member is "inherited" from the generic template to the specialized one.
Parameter Values for Templates Parameter Values for Templates
Besides the template arguments preceded by the class or typename keywords that represent a type, function templates and class templates can include other parameters that are not types whenever they are also constant values, like for example values of fundamental types.
قصاص وائل 168
#include <iostream.h>template <class T, int N> class array { T memblock [N]; public: void setmember (int x, T value); T getmember (int x); };
template <class T, int N>array <T, N>:: setmember (int x, T value) { memblock[x]=value;}
template <class T, int N>T array<T, N>:: getmember (int x) { return memblock[x];}
int main () { array <int,5> myints; array <float,5> myfloats; myints.setmember (0,100); myfloats.setmember (3,3.1416); cout << myints.getmember(0) << '\n'; cout << myfloats.getmember(3) << '\n';}
قصاص وائل 169
1003.1416
It is also possible to set default values for any template parameter just as it is done with function parameters. Some possible template examples seen before:
template <class T> // The most usual: one class parameter.
template <class T, class U> // Two class parameters.template <class T, int N> // A class and an integer.template <class T = char> // With a default value.template <int Tfunc (int)> // A function as parameter.
قصاص وائل 170
Exception handlingException handling
During the development of a program, there may be some cases where we do not have the certainty that a piece of the code is going to work right, either because it accesses resources that do not exist or because it gets out of an expected range, etc...
These types of situations are included in what we consider exceptions and C++ has recently incorporated three new operators to help us handle these situations: try, throw and catch.
try { // code to be tried
throw exception; }
catch (type exception) { // code to be executed in case of exception }
And its operation:
- The code within the try block is executed normally. In case that an exception takes place, this code must use the throw keyword and a parameter to throw an exception. The type of the parameter details the exception and can be of any valid type.
- If an exception has taken place, that is to say, if it has executed a throw instruction within the try block, the catch block is executed receiving as parameter the exception passed by throw.
#include <iostream.h>int main () { char myarray[10]; try { for (int n=0; n<=10; n++) { if (n>9) throw "Out of range"; { myarray[n]='z'; cout<<n<<" ";} } } catch (char * str) { cout << "Exception: " << str << endl; } cout<<"\nfinish"; return 0; }
0 1 2 3 4 5 6 7 8 9 Exception: Out of range finish
قصاص وائل
173
In this example, if within the n loop, n gets to be more than 9 an exception is thrown, since myarray[n] would in that case point to a non-trustworthy memory address. When throw is executed, the try block finalizes right away and every object created within the try block is destroyed. After that, the control is passed to the corresponding catch block (that is only executed in these cases). Finally the program continues right after the catch block, in this case: cout<<"\nfinish"; return 0;
The parameter that catch accepts can be of any valid type. Even more, catch can be overloaded so that it can accept different types as parameters. In that case the catch block executed is the one that matches the type of the exception sent (the parameter of throw):
#include <iostream.h> int main () { try { char * mystring; mystring = new char [10]; if (mystring == NULL) throw "Allocation failure"; for (int n=0; n<=100; n++) { if (n>9) throw n; mystring[n]='z'; } }
catch (int i) { cout << "Exception: "; cout << "index " << i << " is out of range" << endl; }
catch (char * str) { cout << "Exception: " << str << endl; } return 0; }
Exception: index 10 is out of range
قصاص وائل
175
In this case there is a possibility that at least two different exceptions could happen:
That the required block of 10 characters cannot be assigned (something rare, but possible): in this case an exception is thrown that will be caught by catch (char * str).
That the maximum index for mystring is exceeded: in this case the exception thrown will be caught by catch (int i), since the parameter is an integer number.
قصاص وائل 176
Standard exceptions Standard exceptions
Some functions of the standard C++ language library send exceptions that can be captured if we include them within a try block. These exceptions are sent with a class derived from std::exception as type. This class (std::exception) is defined in the C++ standard header file <exception> and serves as a pattern for the standard hierarchy of exceptions:
قصاص وائل 177