Title: Constant Objects and
1Constant Objects and Constant Class
Members Friend Functions and Friend
Classes Static attributes and Static methods
2- Constant object, methods and attributes
- In this lecture we want to bring the concept of
constant to object-oriented design - Before explaining the constant objects, we need
to introduce constant methods and constant
attributes
3- Constant Methods
- A constant method of a class cannot modify any
attribute of that class. It can only print or
access the values for read purpose only. - Consider the following example
void Testinput() cout ltlt enter x
cin gtgt x cout ltlt enter y cin gtgt
y void Testprint() const cout ltlt x
is ltlt x ltlt endl cout ltlt y is ltlt y ltlt
endl
class Test private int x, y
public void input() void print() const
ltSee Example 1gt
4- Any method that is not constant is considered as
a non-constant method in a class. - It is always assumed that a non-constant method
may change the state (value) of the attributes of
the abject - A constant method can only invoke (call) other
constant methods and not non-constant methods. - However, a non-constant method can invoke either
a constant method or a non-constant method. - Any method in a class except constructor and
destructor can be declared constant
5- Constant Attribute (Data members)
- A constant attribute is an attribute in which
once it is initialized to certain value, its
value can not be modified again. - To declare a constant attribute, we place the
word constant just before the declaration of the
attribute. - For example, to declare a constant attribute
called Gender of type char, we can do as follows -
- const char Gender
6- class Child
-
- public
- Child() // empty, default constructor
- Child(char sex, string TheName)
- void print()
-
- private
- const char Gender // cant initialize
Gender in here!! - double WeightAtBirth
- double HieghtAtBirth
- string Name
-
- One cant initialize constant data members in the
class definition. How can we give the Gender data
member the desired default value?
7- Use the member initialization list to initialize
data member when an object is constructed. - ChildChild() Gender('B') // initialization
list -
- WeightAtBirth 8.2 // in pound
- HieghtAtBirth 20 // in inch
- Name "Jim"
-
- You must use the above syntax, the member name
and the value specified in parenthesis.
8- You can also use a value passed in the
constructor argument list to initialize data
members in the initialization list. - ChildChild(char sex, string TheName)
Gender(sex) -
- WeightAtBirth 8.2
- HieghtAtBirth 20
- Name TheName
-
- ltSee Example 2gt
9- If more than one member is to be initialized,
separate the members in the initialization list
by commas. For example, - class Child
-
- public
- Child()
- Child(char sex, string TheName)
- void print()
- private
- const char Gender
- const double WeightAtBirth
- const double HieghtAtBirth
- string Name
ChildChild(char sex, string TheName)
Gender(sex), WeightAtBirth(8.2),
HieghtAtBirth(20) Name TheName ltSee
Example 3gt
10- It is also possible to initialize non-constant
data members right at the initialization list.
For example - class Child
-
- public
- Child()
- Child(char sex, string theName)
- void print()
- private
- const char Gender
- const double WeightAtBirth
- const double HieghtAtBirth
- string Name
ChildChild(char sex, string TheName)
Gender(sex), WeightAtBirth (8.2), HieghtAtBirt
h(20) , Name(theName) ltSee Example 4gt
11- Constant Objects
- A constant object is an object that once it is
declared, the values of its attributes cannot be
changes any more. - Once a constant object is declared, the
constructor is called automatically to initialize
the attributes of that object - After that, a constant object can only invoke
(call) its constant methods and any of its
non-constant methods. - When a not constant object goes out of scope, its
destructor is called. - Constructor and destructors are the only
non-constant methods that a constant object can
invoke. These invocations are done by the system.
12void Timeset_time( int h, int m, int s )
// if time not valid set to 000 hour
minute second 0 if (( h gt 0) (h
lt23 )) hour h if (( m gt 0) (m
lt59 )) minute m if (( s gt 0)
(s lt59) ) second s //----------------
-------------------------------------- void
Timeprint_time() const cout ltlt hour ltlt ""
ltltminute ltlt "" ltlt second if ( hour lt 12 )
cout ltlt " AM" ltlt endl else cout ltlt " PM"
ltlt endl //-------------------------------------
------ int main() const Time theTime
theTime.set_time(2, 30, 34)
theTime.print_time()
Consider the following class definition class
Time public Time() void set_time( int
h, int m, int s ) void print_time() const
private int hour // 0-23 int minute //
0-59 int second // 0-59 //------------------
-------------------------- TimeTime() hour
12 minute 0 second 0
ltSee Example 5gt
!!!!Wont compile
This one is ok
13- Friend Functions and Friend Classes
- A friend function is a function declared outside
of class scope, i.e. its not a member function,
yet has full access to all class members. Even
private data members. - A stand alone function, a class function, or an
entire class may be declared to be a friend to a
class. - Friend functions are most commonly used to
enhance performance.
14- Friend functions are coupled to a class in that
they are aware of implementation issues for the
class. - To declare a friend function, include the
functions prototype in the class definition and
precede it by the keyword friend.
class Count friend void setX( Count c, int
val) public Count() x 0 void
print() cout ltlt x private int x
// non class function, has // access to private
data since //it was declared to be a friend
void setX (Count c, int val ) c.x val
lt See Example 6gt
15- Friendship is granted by a class. For class B to
be a friend of class A, class A must declare that
class B is its friend. - Friendship is not symmetric or transitive.
Because class A declares class B to be its friend
does not mean class A is a friend to class B. - If class A is a friend of class B and class B is
a friend of class C, it does not follow that
class A is a friend of class C. - The next example declares a class to be a friend
16class Class1 public void foo (char c )
... private int y class Class2
friend Class1 // all methods of Class1 are
friends of class2 ... private int
x How about if Class1 wants to make Class2
as its friend as well? See the next example.
17- Consider the following example
- class Class1
-
- friend Class2
- public
- void foo (char c )
- ...
- private
- int y
-
- class Class2
-
- friend Class1 // all methods of Class1 are
friends of class2 - ...
- private
- int x
-
18- To fix this problem, we need to make forward
class declaration of the classes - class Class1
- class Class2
- class Class1
-
- friend Class2
- public
- void foo (char c )
- ...
- private
- int y
-
- class Class2
-
- friend Class1 // all methods of Class1 are
friends of class2 - ...
19- Forward Class Declaration
- A forward class declaration can be thought of as
being similar as a function prototype. It alerts
the compiler that there is a class with that
name. - You cannot create objects with a forward class
declaration since the compiler doesnt know what
constructors are available. - However, you can declare a reference or a pointer
variable to such a class. No object is created
with a reference or a pointer variable. - However, you cannot access methods until the
compiler sees the forward classs full
definition, usually in a header file.
20- Static Class Members
- Normally each object has its own copy of all the
data members. Also, to use a method one must
usually specify the object and then the method
name. - In C there is the concept of class-wide data
members and class-wide methods. To access these
members an object is not needed. - When a value belongs to the class, i.e. it is the
same for all objects. - Use the keyword static to specify that a member
is class wide. Static class members can be public
or private.
21- class Tank
-
- public
- Tank()
- Tank()
- static int num_tanks() return numTanks
- ...
-
- private
- static int numTanks
-
- Static data members must be initialized once at
file scope. Usually in the same file that
implements the class methods
22int TanknumTanks 0 TankTank() numTanks
... TankTank() numTanks -- ... .
23A static method may be called without an object.
For this case, we use the scope resolution
operator. A static method may also be called via
an object. int main() cout ltlt
Tanknum_tanks() ltlt endl Tank t1 cout ltlt
Tanknum_tanks() ltlt endl cout ltlt
t1.num_tanks() ltlt endl ... lt See Example 7gt
24- you can invoke (call) static data members from
any method in a class (static or none static
methods). - However, static methods can only invoke other
static methods. - Regular methods can access any data member,
static or non-static. - However, static methods can only access static
data members and not the non-static data members
25this Pointer
26The this Pointer - In C all objects of a class
have their own copy of data members yet all
objects use the same code for class methods. -
The C compiler uses the this pointer to couple
a method call with the objects data
members. class A public void
set_x(int val) ... private int x
27void Aset_x(int val) x val ... main()
A obj1 A obj2 obj1.set_x(5) // changes
obj1s data member obj2.set_x(10) // changes
obj2s data member - The this pointer, a
pointer to the same type as the methods
class, is implicitly passed as an argument to the
method by the compiler.
28main() A obj1 A obj2 obj1.set_x(ob
j1, 5) // pass address of obj1 obj2.set_x(obj2,
10) // pass address of obj2 - Within the
method the compiler implicitly dereferences the
this pointer to access the data members. void
Aset_x(A this, int val) this-gtx val -
Even though the this pointer is not specified in
the argument list it is accessible to the
programmer. If you wish, you could use this
syntax when implementing a method.
29void Aset_x(int val) this-gtx
val or void Aset_x(int
val) (this).x val // parenthesis are
important!
30Concatenating member function calls - If you
declare a method to return a reference to an
object of the same class, and you return the
this pointer, then its possible to
concatenate method calls.
31class Time public Time() Time set_time(
int h, int m0, int s0 ) Time set_time(
const Time t ) void print_time() const
... Time set_hour(int h) Time set_minute(int
m) Time set_second(int s) ... private
...
32Time Timeset_hour(int h) if ( hrgt0
hrlt23 ) hr h return this ... main(
) Time t t.set_hour(15).set_minunte(30).print
_time() t.set_time(8,30,0).print_time()
33- This works because the member access operator,
., associates from left to right. - for
the object on the left, access the member on the
right - Since t.set_hour(15) returns a Time,
the original this object, we can chain the
next member access on what set_hour()returns.
Thus t.set_time(8,30,0).print_time()
34- first sets the time, set_time(8,30,0), which
returns the this object, and for the this
object call the print_time() method. - You
could do the following as well but it means
making a variable and doing an
assignment. main() Time t Time r
t.set_time(8,30,0) r.print_time()
35Operator Overloading Fundamentals,
Restrictions, and Functions Class Members or
Friends
36Fundamentals of Operator Overloading - C
provides operators, functions which use a symbol
as a name, to be used with primitive data
types. - For example, the multiply function
uses the operator on two operands. - C
overloads these operators. The same operator name
is uses with different operator types. -
ltfloatgt ltfloatgt will perform floating point
arithmetic while ltintgt ltintgt will perform
integer arithmetic. - Also, the symbol can
be used with a pointer variable. It performs
the dereference operation on the pointer. - The
has been overloaded yet again.
37- The context, binary or unary operator, and the
operator types determine which function should
be performed. - C allows programmers to use
the operator syntax on user defined data
types. - Operator overloading, if used
properly, can make code easier to read and
understand.
38class ComplexNumber private float
RealPortion float ImagePortion public
// constructors ComplexNumber() ComplexNu
mber(float, float) // other
methods void GetRealPortion( )
return(RealPortion) void GetImagePortion( )
return(ImagePortion) void add(const
ComplexNumber, const ComplexNumber) ComplexNum
ber operator(const ComplexNumber,
const ComplexNumber)
39main() ComplexNumber n1(1,0)
ComplexNumber n2(1,1) ComplexNumber n3 n3
n1 n2 // with operator overloading ComplexNu
mber tmp tmp.add(n1, n2) // without operator
overloading - C does not allow you to
create new operators, but you can overload
existing operator to use user defined data
types as operands. - To overload an operator use
the keyword operator, the operator symbol, and
specify the data types of the operands.
40ComplexNumber operator(const ComplexNumber
n1, const ComplexNumber n2) float r
n1.RealPortion n2.RealPortion float i
n1.ImagePortion n2.ImagePortion return
ComplexNumber(r,i)
41- To use an operator on class objects you must
overload the operator yourself. Except for two
operators ( , ) which are provided
automatically for every class. - The
operator performs a shallow bit copy of right
hand side (RHS) operand into the left hand side
(LHS) operand. - The returns the
address of the object. - Operator overloading is
used to provide for code clarity. Some
classes, mathematical classes, are naturals for
mathematical operators. - Provide expected
operator functionality. It would confuse
clients if the operator performed an addition.
42Restrictions on Operator Overloading - You
cannot create new operators. For example, There
is no operator in C, you cannot use
this symbol as an operator. - Not every
operator may be overloaded, but most can. -
Fig. 8.1 (pg. 466) shows the operators that can
be overloaded. - Fig. 8.2 (pg.467) shows
the few operators that cannot be overloaded.
They are . . ? sizeof()
43- You can only change the operand type for C
operators - You cannot change the operator
precedence. The operator gets called
before the operator. - You cannot change the
associativity of the operator. For example,
the unary not operator, !, cannot be
changed to ltoperandgt! - Default arguments are
not allowed. You cannot change the number of
operands the operator needs. - You cannot
overload the way C operators function with
built in primitive data types. That is, you
cannot overload ltintgt ltintgt.
44- You can only overload user defined data types
or a mixture of user defined and primitive
data types. ltcomplexgt ltcomplexgt ltcomplexgt
ltintgt ltintgt ltcomplexgt
45Operator Functions Class Members or Friends -
Most operator functions may be class members or
stand alone functions. For efficiency,
non-class operator functions are made friends
of the class. class ComplexNumber friend
ComplexNumber operator(const ComplexNumer n1,
const ComplexNumber n2)
public - If the operator function is not
a member function then the first operand is
the LHS, and the second operand is the RHS.
46ComplexNumber operator(const ComplexNumer
lhs, const ComplexNumber rhs) float r
lhs.GetRealPortion() rhs. GetRealPortion()
float i lhs.GetImagePortion()
rhs.GetImagePortion() return
ComplexNumber(r,i) Main() ComplexNumber
n1(1,0) ComplexNumber n2(1,1) ComplexNumber
n3 n3 n1 n2 - Not all operators can be
stand alone functions. The (), , -gt
and the operators must be class methods.
47- When declaring an operator as a class method
you only specify the RHS operand. The object
is assumed to be the LHS operand. class
ComplexNumber public ComplexNumber(float
r, float i) ComplexNumber operator(const
ComplexNumber n) .... ComplexNumber
ComplexNumberoperator(const ComplexNumer
n) float r RealPortion n.GetRealPortion()
float i ImagePortion n. GetImagePortion()
return ComplexNumber(r,i)
48- You use the same syntax to use a class
operator, there is no need to use the member
access operator . Main() ComplexNumber
n1(1,0) ComplexNumber n2(1,1) ComplexNumber
n3 n3 n1 n2 - If the LHS operand is an
object of a different class or a primitive
type then the operator function must be a stand
alone function.
49Operator Overloading - For the ltlt operator
the LHS must be an ostream. - For the gtgt
operator the LHS must be an istream. - For
performance reasons the stand alone operator
functions for the ltlt and the gtgt operators
are made friends of the class.
50class ComplexNumber friend ostream operator
ltlt (ostream os, const ComplexNumber
c) friend istream operator gtgt (istream is,
const ComplexNumber c)
public ComplexNumber(float r, float
i) ComplexNumber operator( const
ComplexNumber n) .... private double Re
alPortion double ImagePortion
51ostream operatorltlt(ostream os, const
ComplexNumer c) os ltlt ( ltlt c.RealPortion ltlt
, ltlt c.ImagePortion ltlt ) return
os istream operatorgtgt(istream is, const
ComplexNumer c) is gtgt c.RealPortion is gtgt
c.ImagePortion return is void main()
ComplexNumber c cout ltlt Enter the real
imaginary values cin gtgt c cout ltlt c ltlt
is the number entered.
52- By having the ltlt and the gtgt operators
return a stream object we can string together
ltlt and gtgt operator calls. - Its preferred
that operator functions be class methods,
unless forced absolutely necessary. - Make
nonmember operators friends for efficiency.
53Overloading the Operator - The is a
binary operator and must be a class method.
One should use it to access container elements.
- Keep it to the same context as array indexing.
The argument should be an index number. class
MyString public MyString(char Name)
strcpy(str, Name) length strlen(str) char
operator(int i) return stri int
GetLength() return length void data(char
TheString)strcpy(TheString, str)
private int length char str20
54- What should the operator return? In normal
array syntax one can change an element. -
It should be possible to do this with the String
class void main() char StgName20 MyStrin
g s("Heelo") s2 'l' // changes 3rd
element from e to l cout ltlt "The length
is\t" ltlt s.GetLength() ltlt endl s.data(StgName)
cout ltlt "The data is\t" ltlt StgName ltlt
endl lt See Example 8gt
55Overloading Unary Operators - When overloading
unary operator, if it is a class method it
accepts no arguments. The operator works on
the object itself. - If the unary operator is
a stand alone function it accepts one
argument. - The following implementations of
! returns TRUE if the String is empty
(length of 0), FALSE otherwise.
56// UNARY OPERATOR AS CLASS METHOD class MyString
public int operator!() if (length0)
return true else return
false private ... OR // UNARY OPERATOR
AS FRIEND STAND ALONE FUNCTION int operator!(
const MyString s ) if (s.length0) return
true else return false
57void main() MyString s // creates empty
string char TheData20 if ( !s ) cout ltlt
String is empty... else
s.data(TheData) cout ltlt TheData ltlt endl
58- Sometimes not using an operator makes the code
easier to understand. void main() MyString
s // creates empty string if ( s.GetLength()
0 ) cout ltlt String is empty... else co
ut ltlt s.data() ltlt endl ...
59Overloading and - - - Operators and -
- can be pre-fixed or post-fixed. The
following stand alone and class member operator
definitions provide pre-fix syntax.
60// UNARY OPERATOR AS CLASS METHOD class Date
public . Date operator()
increment_day( 1 ) return this
private void increment_day( int numDays ) //
increments the date by one int day int
month int year OR // UNARY OPERATOR AS
FRIEND STAND ALONE FUNCTION Date operator(Date
d ) d.increment_day(1) return d
61 - In C pre-fix and post-fix are two different
operators. - When overloading or - -,
the compiler differentiates the overloaded
operators by an extra dummy argument. - The
following are post-fix or - - operators.
62class Date public ... Date operator()
//pre-fix increment_day( 1 ) return
this Date operator(int dummy)
//post-fix increment_day( 1 ) return
this private void increment_day( int
numDays ) int day int month int year
63OR // STAND ALONE FUNCTIONS Date
operator(Date d) // pre-fix d.increment_day
(1) return d // STAND ALONE FUNCTIONS Date
operator(Date d, int dummy) //
post-fix d.increment_day(1) return d lt
See Example 9gt
64Inheritance
65- Introduction
- Inheritance is a form of software reusability in
which new class are created from the existing
classes. - Software reusability saves time in program and
development - It also encourages the reuse of proven or
debugged high-quality software. - Reducing problems after the system become
functional - When creating a new class, instead of writing
completely new class members, the programmers can
designate the new class is to inherit the data
members previously defined in base class - The new class is called derived class
- Some object-oriented databases and OO-programs
use the terms super-class and sub-class for base
class and derived class, respectively
66Inheritance (2 level)
Student
GraduateStudent
UnderGraduateStudent
Account
SavingAccount
Checking Account
67Inheritance (Multiple level)
CommunityMember
Employee
Student
graduate
Undergraduate
Faculty
Staff
Administration
Teacher
68- Syntax
- To specify that class Faculty is derived from
class Employee, class Faculty would be defined as
follows - class Faculty public Employee
-
-
-
- This is called public inheritance
- All public and protected members of Employee
class is inherited by the Faculty class - Friend functions of class Employee are not
inherited for the class faculty
69- Single/Multiple Inheritance
- Single Inheritance
- The derived class only inherits from one base
class - Multiple Inheritance
- The derived class inherits from more than one
base class - Derived class can also add data members
(attributes and/or methods) of its own.
70- Public Inheritance
- A derived class cannot access the private members
of its base class - Allowing this would violate encapsulation of the
base class - However, a derived class can access private
members of the base only through access functions
provided in the base classs public or protected
interfaces. - We explain protected interfaces shortly.
71- Consider the following examples
class Parent private int x, y public
Parent() void f1( ) void f2( )
class Child public Parent private int z
public Child() void f3( )
72- Class parent has two attributes , x and y,
and three methods. - Class child has three attributes one of its own
and two inherited from parent class) plus five
methods (two of its own and three inherited from
the parent class) - Method f3( ) in the child class can access z
but it cannot directly access x and y,
although x and y have been inherited from the
parent class - If f3() needs to change the status of x and
y, for an object of class child, it has to call
f1() and f2() to do the job for it.
73- To solve this problem, C provides member access
called protected - If a member has a protected access, it is can be
accessed by methods of the derived class, but it
is still protected from any outside objects or
methods outside of its class hierarchy. - Therefore, C provides the protected member
access specifier to allow derived classes free
access to base class members. - Derived class and their friends functions can
access protected members whereas non-friends and
non-derived member functions cannot.
74Example of private/protected member This example
shows that private members of the parent class
cannot be accessed by the methods of the child
class
class Parent private int x, y public
Parent()
class Child public Parent private int z
public Child() void f3( ) //-----------
------------------ void Childf3() z 5 x
10 y 15
This gives compile error because x and y are
private members
75Example of private/protected member This example
shows that protected members of the parent class
can be accessed by the methods of the child class
but not outside of the class scope
class Parent protected int x, y public
Parent()
class Child public Parent private int z
public Child() void f3( ) //-----------
------------------ void Childf3() z 5 x
10 y 15
This does not give any compile error because x
and y are protected members
lt See Examples 10 and 11gt
76- Public, Private, and Protected Inheritance
- Public Inheritance
- Public and protected members of the base class
become public and protected members of the
derived class, respectively - Protected inheritance
- Public and protected members of the base class
become protected members of the derived class - Private inheritance
- Public and protected members of the base class
become private members of the derived class - In all of the above forms, private members of the
base class can only be accessed through the
inherited public or private members (not by the
own members) of the derived class.
77- Constructor in Inheritance
- When an object of the derived class is
instantiated, the constructor of the base class
is called first. Then the constructor of the
derived class is called. - If the base class does not include a constructor,
the default constructor of the base class is
called - If the base class does include a constructor, the
constructor in the derived class can use the
base-class initializer (initializing at the
function header) to call the default constructor
of the base class.
78class Person private string name, int
age public void f1()
class Student public Person private int
stIdentifier public Student() Student
Student() stIdentifier 0
- In this case, when we create an object of the
Student class, the default constructor of the
Person class is called. because the Person class
has no constructor. - ltSee Example 12gt
79class Person private string name, int
age public Person() Person(string,
int) PersonPerson() age 0 name
//------------------------- PersonPerson(s
tring n, int a) age a name
n //-------------------------
class Student public Person private int
stIdentifier public Student(int a, string
n, int sId) StudentStudent(int a, string n,
int sId) Person(a, s) stIdentifier sId
- In this case, when we create an object of the
Student class, the constructor that is determined
by the member initialization list of the Student
class is invoked
ltSee Example 13gt
80- Destructors in Inheritance
- Destructor are called in reverse order of the
constructors. - First the derived class destructor is called,
Then the destructor of the base class is called. - ltSee Example 14gt
81- Redefining Base Class Members
- A derived class data member with the same name as
a base class data member will hide the base class
data member in derived class methods. - This does not apply to private base class
members, since they are not accessible to the
derived class any ways. - You can use the scope resolution operator to
access base class members which are overridden by
the derived class. - Derived class methods with the exact same
signature as a base class method override the
base class method when accessed via a derived
class object (regular variable, pointer or
reference).
82class Person public string name void f1( )
cout ltlt "This is f1( ) in Person"ltlt
endl class Employee public
Person public string name void f1( ) cout
ltlt "This is f1( ) in Employee"ltlt endl
83void main () Person p Employee
e e.name "Bob" // sets the specialized
name to Bob e.f1( ) // calls the
specialized name e.Personname "Jim" //
sets the inherited name to Jim
e.Personf1() // calls the inherited method
f1() The output is This is f1( ) in
Employee This is f1( ) in Person ltSee Example
15gt