CIS 22B – Lecture 2
CIS 22C – Recap of Objects
Manish Goel
Classes – Recap
Abstraction & Encapsulation Data Hiding
Abstraction & Typing Abstract Data Types
Access Specifiers private, protected, public
Member functions – accessors, mutators, iterators, overloading
Static members class “global”
Instantiation – Classes Objects
Constructors – default, overloading
Destructors – default
Object composition
Classes – Recap (2)
“Friendship” – privileged access
this pointer
Inheritance Abstraction, Modularity, Hierarchy
Base Class Derived Class(es)
All base class functionality exists in derived class
Inherited access can be limited
Specialization Extend class functionality in derived class
Polymorphism Over-riding uniqueness, individuality of derived classes automatically “morph” from one peer form to another peer form
Class Hierarchies
A base class can be derived from another base class.
Redefining Base Class Functions
Redefining function: function in a derived class that has the same name and parameter list as a function in the base class
Typically used to replace a function in base class with different actions in derived class
Not the same as overloading – with overloading, parameter lists must be different
Objects of base class use base class version of function; objects of derived class use derived class version of function
5
Problem with Redefining
Consider this situation:
Class BaseClass defines functions x() and y(). x() calls y().
Class DerivedClass inherits from BaseClass and redefines function y().
An object D of class DerivedClass is created and function x() is called.
When x() is called, which y() is used, the one defined in BaseClass or the the redefined one in DerivedClass?
Object D invokes function X() in BaseClass. Function X() invokes function Y() in BaseClass, not function Y() in DerivedClass, because function calls are bound at compile time. This is static binding.
DerivedClass
void X();
void Y();
void Y();
DerivedClass D;
D.X();
Polymorphism and Virtual Member Functions
Virtual member function: function in base class that expects to be redefined in derived class
Function defined with key word virtual:
virtual void Y() {…}
Supports dynamic binding: functions bound at run time to function that they call
in our prior example, such a signature will result in derived class Y() being called with virtual keyword
At runtime, C++ determined the type of object making the call and bound the function to appropriate version – this type of behavior is known as polymorphism. The term polymorphism means the ability to take many forms.
Without virtual member functions, C++ uses static (compile time) binding
7
Redefinition cannot use Base Class Pointers
#include
using namespace std;
class CPolygon
{
protected:
int width, height;
public:
void setup (int first, int second)
{
width= first;
height= second;
}
};
class CRectangle: public CPolygon
{
public:
int area()
{ return (width * height); }
};
class CTriangle: public CPolygon
{
public:
int area()
{ return (width * height / 2); }
};
int main ()
{
CRectangle rectangle;
CTriangle triangle;
CPolygon* ptr_polygon1 = &rectangle;
CPolygon* ptr_polygon2 = ▵
ptr_polygon1->setup(2,2);
ptr_polygon2->setup(2,2);
cout << rectangle.area() << endl;
cout << triangle.area() << endl;
return 0;
}
Courtesy: www.codingunit.com
Polymorphism Requires References or Pointers
Polymorphic behavior is only possible when an object is referenced by a reference variable or a pointer.
Can define a pointer to a base class object and assign it the address of a derived class object
Static binding - Base class pointers and references only know about members of the base class, so you can’t use a base class pointer to call a derived class function
Dynamic binding - Redefined functions in derived class are called with base class pointer because base class declares the function virtual – this is “over-riding”
So a virtual function is dynamically bound and over-ridden and non-virtual function is statically bound and redefined
Polymorphism with Base Class Pointers
#include
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void setup (int first, int second) {
width= first;
height= second;
}
virtual int area()
{ return (0) };
};
class CRectangle: public CPolygon {
public:
int area()
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area()
{ return (width * height / 2); }
};
int main ()
{
CRectangle rectangle;
CTriangle triangle;
CPolygon polygon;
CPolygon* ptr_polygon1 = &rectangle;
CPolygon* ptr_polygon2 = ▵
CPolygon* ptr_polygon3 = &polygon;
ptr_polygon1->setup(2,3);
ptr_polygon2->setup(2,2);
ptr_polygon3->setup(2,2);
cout << ptr_polygon1->area() << endl;
cout << ptr_polygon2->area() << endl;
cout << ptr_polygon3->area() << endl;
return 0;
}
Courtesy: www.codingunit.com
Virtual Destructors
It's a good idea to make destructors virtual if the class could ever become a base class.
Otherwise, the compiler will perform static binding on the destructor if the class ever is derived from.
Destructor – Static Binding Destructor – Dynamic Binding
class Base
{
public:
~Base() {cout << “Delete Parent\n”;}
};
class Derived : public Base
{
public:
~Derived() {cout << “Delete Child\n;}
int main()
{
Base *b = new Derived;
delete b;
}
class Base
{
public:
virtual ~Base()
{cout << “Delete Parent\n”;}
};
class Derived : public Base
{
public:
~Derived() {cout << “Delete Child\n;}
int main()
{
Base *b = new Derived;
delete b;
}
Abstract Base Classes and Pure Virtual Functions
Pure virtual function: a virtual member function that must be overridden in a derived class that has objects
Abstract base class contains at least one pure virtual function:
virtual void Y() = 0;
The “= 0” indicates a pure virtual function
Must have no function definition in the base class
Abstract base class: class that cannot be instantiated, i.e. can have no objects. Serves as a basis for derived classes that may/will have objects.
A class becomes an abstract base class when one or more of its member functions is a pure virtual function
12
Polymorphism – Abstract Base Classes
#include
using namespace std;
class CPolygon
{
protected:
int width, height;
public:
void setup (int first, int second)
{
width= first;
height= second;
}
virtual int area() = 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 rectangle;
CTriangle triangle;
CPolygon* ptr_polygon1 = &rectangle;
CPolygon* ptr_polygon2 = ▵
ptr_polygon1->setup(2,2);
ptr_polygon2->setup(2,2);
cout << ptr_polygon1->area() << endl;
cout << ptr_polygon2->area() << endl;
return 0;
}
Courtesy: www.codingunit.com
Abstract Base Classes with Dynamic Allocation
#include
using namespace std;
class CPolygon
{
protected:
int width, height;
public:
void setup (int first, int second)
{
width= first;
height= second;
}
virtual int area(void) = 0;
void onscreen(void)
{ cout << this->area() << endl; }
};
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 ()
{
CPolygon *ptr_polygon1 = new CRectangle;
CPolygon *ptr_polygon2 = new CTriangle;
ptr_polygon1->setup(2,2);
ptr_polygon2->setup(2,2);
ptr_polygon1->onscreen();
ptr_polygon2->onscreen();
delete ptr_polygon1;
delete ptr_polygon2;
return 0;
}
Courtesy: www.codingunit.com
Inheritance Models
Courtesy: www.codingunit.com
Multiple Inheritance
A derived class can have more than one base class
Each base class can have its own access specification in derived class’s definition:
class Teacher: public Person, public Employee;
Arguments can be passed to both base classes’ constructors:
Teacher(string strName, int nAge, bool bIsMale, string strEmployer, double dWage, int nTeachesGrade)
: Person(strName, nAge, bIsMale), Employee(strEmployer, dWage),
m_nTeachesGrade(nTeachesGrade
Base class constructors are called in order given in class declaration, not in order used in class constructor
class
Person
class
Employee
class
Teacher
16
#include
#include
using namespace std;
class Person
{
private:
string m_strName;
int m_nAge;
bool m_bIsMale;
public:
Person(string strName, int nAge,
bool bIsMale) : m_strName(strName),
m_nAge(nAge), m_bIsMale(bIsMale) { }
string GetName() { return m_strName; }
int GetAge() { return m_nAge; }
bool IsMale() { return m_bIsMale; }
};
class Employee
{
private:
string m_strEmployer;
double m_dWage;
public:
Employee(string strEmployer, double
dWage) : m_strEmployer(strEmployer),
m_dWage(dWage) { }
string GetEmployer()
{ return m_strEmployer; }
double GetWage() { return m_dWage; }
};
// Teacher publicly inherits Person and Employee
class Teacher: public Person, public Employee
{
private:
int m_nTeachesGrade;
public:
Teacher(string strName, int nAge,
bool bIsMale, string strEmployer,
double dWage, int nTeachesGrade)
: Person(strName, nAge, bIsMale),
Employee(strEmployer, dWage),
m_nTeachesGrade(nTeachesGrade) { }
};
int main()
{
Teacher T(“MG”, 47, 1, “DeAnza”, 500, 5);
cout << "Teacher's Name: " << T.GetName() << endl;
cout << "Teacher's Age: " << T.GetAge() << endl;
cout << "Teacher's Employer: " << T.GetEmployer() << endl;
cout << "Teacher's Salary: " << T.GetWage() << endl;
return 0;
}
Courtesy: www.learncpp.com
Multiple Inheritance
Problem: what if base classes have member variables/ functions with the same name?
Solutions:
Derived class redefines the multiply-defined function
Derived class invokes member function in a particular base class using scope resolution operator ::
Compiler errors occur if derived
class uses base class function
without one of these solutions
Programmers try to avoid multiple
inheritance to keep modeling simple
#include
using namespace std;
class Monitor
{
private:
long m_lID;
public:
Monitor (long lID) : m_lID(lID) { }
long GetID() { return m_lID; }
};
class CPU
{
private:
long m_lID;
public:
CPU (long lID) : m_lID(lID) { }
long GetID() { return m_lID; }
};
class LabComputer: public Monitor, public CPU
{
public:
LabComputer (long lUSBID, long lNetworkID)
: Monitor (lUSBID), CPU (lNetworkID) { }
};
int main()
{
LabComputer c54G(5442, 181742);
cout << c54G.GetID(); // Which GetID()
return 0;
} #include
using namespace std;
class Monitor
{
private:
long m_lID;
public:
Monitor (long lID) : m_lID(lID) { }
long GetID() { return m_lID; }
};
class CPU
{
private:
long m_lID;
public:
CPU (long lID) : m_lID(lID) { }
long GetID() { return m_lID; }
};
class LabComputer: public Monitor, public CPU
{
public:
LabComputer (long lUSBID, long lNetworkID)
: Monitor (lUSBID), CPU (lNetworkID) { }
};
int main()
{
LabComputer c54G(5442, 181742);
cout << c54G.CPU::GetID(); // Correct Way
return 0;
}
Courtesy: www.learncpp.com
The this Pointer
this: predefined pointer available to a class’s member functions
Always points to the instance (object) of the class whose function is being called
Is passed as a hidden argument to all non-static member functions
Can be used to access members that may be hidden by parameters with same name
class SomeClass
{
private:
int num;
public:
void setNum(int num)
{ this->num = num; }
…
};
20
Operator Overloading
Operators such as =, +, and others can be redefined when used with objects of a class
The name of the function for the overloaded operator is operator followed by the operator symbol, e.g.,
operator+ to overload the + operator, and
operator= to overload the = operator
Prototype for the overloaded operator goes in the declaration of the class that is overloading it
Overloaded operator function definition goes with other member functions
Prototype: void operator=(const SomeClass &rval)
return
type
function
name
parameter for
object on right
side of operator
21
Operator Overloading – things to consider
At least one operand for an overloaded operator must be a user defined type
Only existing operators can be overloaded
e.g. “**” cannot be defined to calculate exponent
Operator overloading cannot change operator precedence and associativity
i.e. an exponent operator will be calculated before addition
When evaluating an expression with operators:
If operands are built-in types, C++ calls built-in routines
If any operand is UDT, C++ checks for overloaded operator function
Otherwise results in compiler error
Invoking an Overloaded Operator
Operator is called via object on left side
Operator can be invoked as a member function:
object1.operator=(object2);
It can also be used in more conventional manner:
object1 = object2;
Return type the same as the left operand
Supports notation like:
object1 = object2 = object3;
Function declared as follows:
const SomeClass operator=(const someClass &rval)
In function, include as last statement:
return *this;
23
Returning a Value
Overloaded operator can return a value
class Point2d
{
public:
double operator-(const point2d &right)
{ return sqrt(pow((x-right.x),2)
+ pow((y-right.y),2)); }
…
private:
int x, y;
};
Point2d point1(2,2), point2(4,4);
// Compute and display distance between 2 points.
cout << point2 – point1 << endl; // displays 2.82843
24
More on Overloaded Operators
Can change meaning of an operator
Cannot change the number of operands of the operator
Most mathematical operators can be overloaded.
++, -- operators overloaded differently for prefix vs. postfix notation
Overloaded relational operators should return a bool value
Overloaded stream operators >>, << must return reference to istream, ostream objects and take istream, ostream objects as parameters
Cannot overload the following operators:
?: . .* :: sizeof
25
Overloaded [] Operator
Can create classes that behave like arrays
e.g. string class char array
Elements of string accessed similar to elements of char array because the char array is a member of the string
string sName = “William”;
cout << sName[0]; // prints ‘W’ (char)
// similar to sName.m_char[0] = ‘W’
Overloaded [] provide bounds-checking on subscripts
Must consider constructor, destructor for array allocation / destruction
Overloaded [] returns a reference to object, not an object itself, i.e. sName[0] <> sName
26
Cannot Access Private Member Array Write Setter’s and Getter’s for manipulating private member array Overload [ ] to make class behave like array
class IntList
{
private:
int m_anList[10];
};
int main()
{
IntList cMyList;
return 0;
}
class IntList
{
private:
int m_anList[10];
public:
void SetItem(int nIndex, int nData)
{ m_anList[nIndex] = nData; }
int GetItem(int nIndex)
{ return m_anList[nIndex]; }
};
int main()
{
IntList cMyList;
cMyList.SetItem(2, 3);
return 0;
}
class IntList
{
private:
int m_anList[10];
public:
int& operator[] (const int nIndex);
};
int& IntList::operator[] (const int nIndex)
{
return m_anList[nIndex];
}
int main()
{
IntList cMyList;
cMyList[2] = 3; // set a value
cout << cMyList[2]; // get a value
return 0;
}
Object Conversion
Type of an object can be converted to another type
Automatically done for built-in data types
Must write an operator function to perform conversion
To convert an FeetInches object to an int or double:
FeetInches::operator int()
{return feet;}
FeetInches::operator double()
{ double temp = feet;
temp += (inches / 12.0);
return temp; }
Assuming distance is a FeetInches object, allows statements like:
int i = distance;
double d = distance;
28
Exceptions
Indicate that something unexpected has occurred or been detected
Allow program to deal with the problem in a controlled manner
Can be as simple or complex as program design requires
Exception: object or value that signals an error
Throw an exception: send a signal that an error has occurred
Catch/Handle an exception: process the exception; interpret the signal
Exceptions – How they work
throw – followed by an argument, is used to throw an exception
try – followed by a block { }, is used to invoke code that throws an exception
catch – followed by a block { }, is used to detect and process exceptions thrown in preceding try block. Takes a parameter that matches the type thrown.
A function that throws an exception is called from within a try block
If the function throws an exception, the function terminates and the try block is immediately exited. A catch block to process the exception is searched for in the source code immediately following the try block.
If a catch block is found that matches the exception thrown, it is executed. If no catch block that matches the exception is found, the program terminates.
Exceptions – Example
// function that throws an exception
int totalDays(int days, int weeks)
{
if ((days < 0) || (days > 7))
throw “invalid number of days”;
// the argument to throw is the character string
else
return (7 * weeks + days);
}
// in the caller or main
try // block that calls function
{
totDays = totalDays(days, weeks);
cout << "Total days: " << days;
}
catch (char *msg) //interpret exception from char string passed
{
cout << "Error: " << msg;
}
From Program 16-1
From Program 16-1
What Happens in theTry/Catch Construct
What if no exception is thrown?
Exceptions - Notes
Predefined functions such as new may throw exceptions
Value thrown does not need to be used in catch block.
so, no name is needed in catch parameter definition
catch block parameter definition does need the type of exception being caught
An exception will not be caught if
it is thrown from outside of a try block
there is no catch block that matches the data type of the thrown exception
If an exception is not caught, the program will terminate
Exceptions – Notes (2)
Once an exception is thrown, the program cannot return to throw point. The function executing throw terminates (does not return), other calling functions in try block terminate, resulting in unwinding the stack
If objects were created in the try block and an exception is thrown, they are destroyed.
Nested try blocks – try/catch blocks can occur within an enclosing try block. Exceptions caught at an inner level can be passed up to a catch block at an outer level:
catch ( )
{
...
throw; // pass exception up
} // to next level
Exceptions and Objects
An exception class can be defined in a class and thrown as an exception by a member function
An exception class may have:
no members: used only to signal an error
members: pass error data to catch block
A class can have more than one exception class
38
Contents of Rectangle.h (Version1) (Continued)
Program 16-2 (Continued)
Function Templates
Function template: a pattern for a function that can work with many data types
When written, parameters are left for the data types
When called, compiler generates code for specific data types in function call
45
Function Template Example
template
T times10(T num)
{
return 10 * num;
}
template
prefix
generic
data type
type
parameter
What gets generated when times10 is called with an int: What gets generated when times10 is called with a double:
int times10(int num)
{
return 10 * num;
} double times10(double num)
{
return 10 * num;
}
46
Function Template Example
template
T times10(T num)
{
return 10 * num;
}
Call a template function in the usual manner:
int ival = 3;
double dval = 2.55;
cout << times10(ival); // displays 30
cout << times10(dval); // displays 25.5
47
Function Template Notes
Can define a template to use multiple data types:
template
Example:
template
double mpg(T1 miles, T2 gallons) // replaced in the
{ // called function
return miles / gallons // with the data
} // types of the
// arguments
48
Function Template Notes
Function templates can be overloaded Each template must have a unique parameter list
template
T sumAll(T num) …
template
T1 sumall(T1 num1, T2 num2) …
49
Function Template Notes
All data types specified in template prefix must be used in template definition
Function calls must pass parameters for all data types specified in the template prefix
Like regular functions, function templates must be defined before being called
50
Function Template Notes
A function template is a pattern
No actual code is generated until the function named in the template is called
A function template uses no memory
When passing a class object to a function template, ensure that all operators in the template are defined or overloaded in the class definition
51
Where to Start
When Defining Templates
Templates are often appropriate for multiple functions that perform the same task with different parameter data types
Develop function using usual data types first, then convert to a template:
add template prefix
convert data type names in the function to a type parameter (i.e., a T type) in the template
Class Templates
Classes can also be represented by templates. When a class object is created, type information is supplied to define the type of data members of the class.
Unlike functions, classes are instantiated by supplying the type name (int, double, string, etc.) at object definition
53
Class Template Example
template
class grade
{
private:
T score;
public:
grade(T);
void setGrade(T);
T getGrade()
};
Class Template Example
Pass type information to class template when defining objects:
grade
grade
Use as ordinary objects once defined
Class Templates and Inheritance
Class templates can inherit from other class templates:
template
class Rectangle
{ … };
template
class Square : public Rectangle
{ … };
Must use type parameter T everywhere base class name is used in derived class
56
/docProps/thumbnail.jpeg