Generic Programming: Templates and Overloading - PowerPoint PPT Presentation

About This Presentation
Title:

Generic Programming: Templates and Overloading

Description:

Generic Programming: Templates and Overloading – PowerPoint PPT presentation

Number of Views:89
Avg rating:3.0/5.0
Slides: 96
Provided by: ust99
Category:

less

Transcript and Presenter's Notes

Title: Generic Programming: Templates and Overloading


1
Generic ProgrammingTemplates and Overloading
2
Evolution of Reusability and Genericity
  • Major theme in development of programming
    languages
  • Reuse code to avoid repeatedly reinventing the
    wheel
  • Trend contributing to this
  • Use of generic code
  • Can be used with different types of data
  • Function and class templates
  • Enable programmers to specify an entire range of
    related functions and related classes
  • ? Generic programming

COMP152
2
3
Function Templates (parameterized functions)
4
Motivation
  • Initially code was reusable by encapsulating it
    within functions
  • Example
  • Write
  • Then call swap(x,y)

void swap (int first, int second) int temp
first first second second temp
COMP152
4
5
  • To swap variables of different types, write
    another function
  • Overloading allows functions to have same name
  • Signature (types and numbers of parameters) keep
    them unique to the compiler
  • This could lead to a library of swap functions
  • One function for each standard/primitive type
  • Compiler chooses which to use from signature
  • But what about swapping user defined types such
    as an object?
  • We cannot cover the swap function for ALL
    possible class objects

void swap (int first, int second) int temp
first first second second temp
void swap (double first, double second)
double temp first first second second
temp
void swap (char first, char second) char
temp first first second second temp
COMP152
5
6
Passing Types (Instead of Fixed Types)
void swap (T first, T second) T temp
first first second second temp
COMP152
6
7
  • Using function overloading, note how similar each
    of the swap functions would be
  • The three places where the type is specified
  • What if we passed the type somehow?
  • Templates make this possible
  • Declare functions that receive both data and
    types via parameter
  • Thus code becomes more generic
  • Easier to reuse and extend to other types

COMP152
7
8
Function Templates
  • Produce overloaded functions that perform
    identical operations/algorithms on different
    types of data
  • Programmer writes a single function-template
    definition
  • Compiler generates separate object-code functions
    (function-template specializations) based on
    argument types in calls to the function template

COMP152
8
9
Function Templates
  • More compact and convenient form of overloading
  • Identical program logic and operations/algorithms
    for each data type
  • Function template definition
  • Written by programmer once
  • Essentially defines a whole family of overloaded
    functions
  • Begins with the template keyword
  • Contains template parameter list of formal type
    parameters for the function template enclosed in
    angle brackets (ltgt)
  • Formal type parameters
  • Preceded by keyword typename or keyword class
  • Placeholders for fundamental types or
    user-defined types

COMP152
9
10
Writing Template
  • A function template is a pattern
  • constructed based on given actual types
  • type parameter said to be "bound" to the actual
    type passed to it
  • Calling a function with template type inside the
    function

templatelttypename Tgt void f() T a
f()
COMP152
10
11
General Form of Template
  • templatelttypename TypeParamgt
  • FunctionDefinition
  • TypeParam is a type-parameter (placeholder)
    naming the "generic" type of value(s) on which
    the function operates
  • FunctionDefinition is the definition of the
    function, using type TypeParam

COMP152
11
12
templatelttypename Tgt void swap (T first, T
second) T temp first first second
second temp main() int a,b double
x,y char m,n swap(a,b) //
swapltintgt(a,b) swap(x,y) // swapltdoublegt(x,y)
swap(m,n) // swapltchargt(m,n)
COMP152
12
13
Template Instantiation
  • In and of itself, the template does nothing
  • When the compiler encounters a template
  • it stores the template
  • but doesn't generate any machine instructions or
    codes
  • When a function template is instantiated
  • Compiler finds type parameters in list of
    function template
  • For each type in the function parameter list,
    type of corresponding argument is determined
  • These two function type and argument type are
    then bound together
  • E.g., when it encounters a call to swap()
  • Example swap(int, int)
  • it generates an integer instance of swap()
  • The type will be determined
  • by the compiler (at compilation time)
  • from the type of the arguments passed
  • when swap() is called
  • Cannot specify data type at run time

COMP152
13
14
Example displayarray.cpp
template lttypename Tgt void display(T array, int
num) for (int i 0 i lt num i)
cout ltlt arrayi ltlt " " cout ltlt endl int
main() double x 1.1, 2.2, 3.3, 4.4,
5.5 display(x, 5) int num 1, 2, 3,
4 display(num, 4)
displayltdoublegt created
displayltintgt created
1.1 2.2 3.3 4.4 5.5 1 2 3 4
  • Function-template specializations are generated
    automatically by the compiler to handle each type
    of call to the function template
  • If an array of user-defined objects is used, need
    to overload ltlt operator of the object class.

COMP152
14
15
.h and .cpp Files for Template Functions
A function template cannot be split across files
for separate compilation - Specification/declarati
on and implementation/definition usually are in
the same file - This sometimes causes some
inconvenience in makefiles (need to combine .h
and .cpp)
  • Three files
  • foo.h (template declaration),
  • foo.cpp (template definition), and
  • main.cpp (using template functions)
  • The compiler, in the compilation of foo.cpp to
    object codes, has to know the data type input
    into the template functions, and replace all the
    template occurrences by the actual data type
  • Therefore, the callers of the template functions
    have to be known at compile time. This is
    different from the non-template functions where
    the compiler does not need to know the callers to
    generate proper object codes.
  • That means main.cpp has to include both
    foo.cpp,and hence foo.h
  • That also means foo.h and foo.cpp have to be
    combined into one single file

COMP152
15
16
Class Templates (parameterized classes)
17
Motivations
  • class List
  • public
  • List() // constructor
  • List(const list list) // copy
    constructor
  • List() // destructor
  • bool empty() const // boolean
    function
  • int head() const // access
    functions
  • void add(int newdata) // add to the
    head
  • void delete() // delete the
    head
  • private

List of integer, list of doubles, list of
characters, list of objects
18
  • class List
  • public
  • List() // constructor
  • List(const list list) // copy
    constructor
  • List() // destructor
  • bool empty() const // boolean
    function
  • T head() const // access
    functions
  • void add(T newdata) // add to the head
  • void delete() // delete the
    head
  • private

19
  • templatelttypename Tgt
  • class List
  • public
  • List()
  • List(const List list1)
  • list()
  • bool empty() const
  • T head() const
  • void add(T newdata)
  • void delete()
  • private
  • T head

20
Implementation
Some simple member functions
  • templatelttypename Tgt
  • ListList()
  • headNULL size0
  • templatelttypename Tgt
  • bool Listempty() const
  • templatelttypename Tgt
  • T Listhead() const

21
Other functions
templatelttypename Tgt ListList() delete T
head
22
How about using typedef ?
  • Changes the header file
  • Any program that uses this must be recompiled ?
    inconvenient and time-consuming
  • A name declared using typedef can have only one
    meaning
  • What if we need two stacks of different types in
    the same program?

COMP152
22
23
General Form of Class Template
templatelttypename Tgtclass X
Xlttgt A
  • More than one type parameter may be specified

templatelttypename T1, ..., typename Tngtclass
X
Xltt1, ...,tngt B
23
COMP152
24
Instantiating Class Templates
  • Instantiate by using declaration of form
  • ClassNameltTypegt object
  • Examples
  • Listltintgt intList
  • Listltstringgt stringList
  • Compiler will generate two distinct definitions
    of List
  • two instances one for int and one for strings

COMP152
24
25
Rules For Class Templates
  • Definitions of member functions outside class
    declaration must be function templates
  • tempatelttypname Tgt A_classltTgt
  • All uses of class name as a type must be
    parameterized with ltgt
  • A_classltTgt
  • (compared to function template, the type is
    deduced)
  • Member functions must be defined in the same file
    as the class declaration
  • Same reason as in function template (i.e.,
    compiler needs to know the exact data types at
    calling to generate appropriate object codes at
    compile time)
  • Sometimes causing inconveniences in makefile
    (need to combine .h and and .cpp)

COMP152
25
26
Stack Class Template
  • Application of all these principles
  • A Stack class template (Stack.h)
  • Note that there is not a separate .cpp file
  • Templates may have more than one type parameter
  • Thus possible to specify a Stack class
    differently
  • Could specify with a dynamic array and pass an
    integer for the capacity

COMP152
26
27
stacktester1.cpp Output
  • Sample Output

Pushing elements onto doubleStack 1.1 2.2 3.3 4.4
5.5 Stack is full. Cannot push 6.6 Popping
elements from doubleStack 5.5 4.4 3.3 2.2
1.1 Stack is empty. Cannot pop Pushing elements
onto intStack 1 2 3 4 5 6 7 8 9 10 Stack is full.
Cannot push 11 Popping elements from intStack 10
9 8 7 6 5 4 3 2 1 Stack is empty. Cannot pop
COMP152
27
28
stacktester2.cpp Sample Output
Pushing elements onto doubleStack 1.1 2.2 3.3 4.4
5.5 Stack is full. Cannot push 6.6   Popping
elements from doubleStack 5.5 4.4 3.3 2.2
1.1 Stack is empty. Cannot pop   Pushing elements
onto intStack 1 2 3 4 5 6 7 8 9 10 Stack is full.
Cannot push 11   Popping
elements from intStack 10 9 8 7 6 5 4 3 2 1 Stack
is empty. Cannot pop
COMP152
28
29
Default Types
  • Type parameters can have default arguments
  • Template header
  • templatelttypename T stringgt
  • Declaration
  • Stackltgt myStringStack // default is string

COMP152
29
30
Other Parameters
  • Other primitive types (not a generic type) can be
    parameters of the template
  • Can have default arguments
  • Are treated as consts to generate machine codes
  • Template header
  • templatelttypename T, int numbergt
  • Declaration
  • Stackltdouble, 100gt myDoubleStack

COMP152
30
31
Templates and Static Members
  • Each class-template specialization has its own
    copy of each static data member
  • All objects of that specialization share that one
    static data member
  • static data members must be defined and, if
    necessary, initialized at file scope
  • Each class-template specialization gets its own
    copy of the class templates static member
    functions
  • See special_template.cpp for default and static
    members

COMP152
31
32
(Explicit) Specializations
  • Used when a particular type will not work with
    the general template or requires customized
    processing
  • Example for an explicit StackltEmployeegt
    specialization, where Employee is a defined class
  • This is a complete replacement for the general
    template
  • This does not use anything from the original
    class template and can even have different
    members

templateltgtclass StackltEmployeegt //
tailor-made implementation here
COMP152
32
33
Example
templatelttypename Tgt class X templateltgt clas
s Xltintgt public void hello(void) // No
need to have templateltgt here void
Xltintgthello(void) cout ltlt "hello world" ltlt
endl int main() Xltintgt a a.hello()
COMP152
33
34
  • Overloading
  • Functions overloading
  • Operator overloading

35
Function overloading
36
Function Overloading
  • Overloaded functions have
  • Same name
  • Different sets of parameters
  • Compiler selects proper function to execute based
    on number, types and order of arguments in the
    function call
  • Commonly used to create several functions of the
    same name that perform similar tasks, but on
    different data types and numbers of parameters

COMP152
36
37
overload.cpp (1/2)
  • Defining a square function for ints and doubles

// function square for int values int square(int
x) cout ltlt "square of integer " ltlt x ltlt "
is " return x x // end function square
with int argument // function square for double
values double square(double y) cout ltlt
"square of double " ltlt y ltlt " is " return y
y // end function square with double argument
COMP152
37
38
overload.cpp (2/2)
  • Sample Output
  • Output confirms that the proper function was
    called in each case

int main() cout ltlt square( 7 ) // calls int
version cout ltlt endl cout ltlt square( 7.5
) // calls double version cout ltlt endl
return 0 // indicates successful termination
// end main
square of integer 7 is 49 square of double 7.5 is
56.25
COMP152
38
39
More examples ...
  • include ltstdio.hgt
  • int max(int a, int b)
  • if (a gt b) return a
  • return b
  • char max(char a, char b)
  • if (strcmp(a, b) gt 0) return a
  • return b
  • int main()
  • cout ltlt max(19, 69) ltlt max(19, 69) ltlt
    endl
  • cout ltlt max(abc, def) ltlt max(abc,
    def) ltlt endl

40
Function Overloading
  • How the compiler differentiates overloaded
    functions
  • Overloaded functions are distinguished by their
    signatures
  • Compiler encodes each function identifier with
    the number and types of its parameters to enable
    type-safe linkage
  • Type-safe linkage ensures that
  • Proper overloaded function is called
  • Types of the arguments conform to types of the
    parameters
  • Creating overloaded functions with identical
    parameter lists and different return types is a
    compilation error
  • It is ambiguous on which function to call

COMP152
40
41
Operator overloading part I (good for users,
hard for developpers ?
42
Motivation
class Complex public Complex(double re,
double im) const const Complex add(const
Complex c2) return (Complex()) p
rivate double real double imag Complex
add(const Complex c1, const Complex c2)
return Complex(,) main() Complex
a,b,c ca.add(b) // member function cadd(a,b
) // non-member (global) function
42
43
Operator Overloading a syntax sugar!
is a function (operator function), is called
operator, and can be overloaded!
23 is operator(2,3)
ab is operator(a,b) or a.operator(b)
a member function
a (global) non-member function
43
44
addition operator of two complex numbers
obj1.add(obj2) ? obj1 obj2
class Complex public const Complex
operator(const Complex c2) return
Complex() main() Complex
a,b,c cab
The form of ab is translated into a.operator(b)
44
45
But,
  • abc is fine a.add(b.add(c))
  • a10.0 is fine (if we modify it )
    a.operator(10.0)
  • How about 10.0a ? 10.0.operator(a)?

45
46
Use a non-member function
If the first operand (or the left operand) is not
an object of the same class, we cannot use a
member function, so have to use a normal
overloaded function.
class Complex public double real()
const double imag() const const Complex
operator(const Complex c2) const Complex
operator(const double real2) Complex
operator(const double real1, const Complex c2)
return Complex(real(),imag()) const
Complex operator(const Complex c1, const
Complex c2) return Complex(real(),imag())
main() Complex a,b,c c10.0a ca10.0
  • A call of ab is then converted to operator(a,b)
  • 10.0a ? operator(10.0,a) (a normal function
    call, not a method of an object)

46
47
Friend is coming to help
  • We can define functions or classes to be friends
    of a class to allow them direct access to its
    private data members
  • class Complex
  • ...
  • public
  • ...
  • friend const Complex operator(const
    Complex, const Complex)
  • const Complex operator(const Complex op1,
    const Complex op2)
  • double real c1.real c2.real
  • double imag c1.imag c2.imag
  • return(Complex(real, imag))

Access to private data thanks to the friendship!
47
48
Assignment Operator
A a,b a b
  • Assignment operator () can be used to assign an
    object to another object of the same type
  • Member-wise assignment each data member of the
    right object is assigned to the same data member
    in the left object

COMP152
48
49
  • class T
  • ...
  • public
  • ...
  • T operator(const T right)
  • ...
  • T Toperator(const T right)
  • return this
  • main()
  • T a,b
  • b a // b.operator(a)

it can NOT be a const function, as modifies
the object
this refers to the calling object Returning a
reference allows the chaining of operators a b
c d ? a (b (c d)) ?
a.operator(b.operator(c.operator(d)))
49
50
Return an object or a reference?
  • class T
  • ...
  • public
  • ...
  • T operator(const T right)
  • ...
  • T Toperator(const T right)
  • return this
  • T Toperator(const T right)
  • if (this right) return this
  • return this
  1. Return an object make a temporary object, then
    return
  2. Return a ref no copy, just the ref. ? more
    efficient!

50
51
Returning a reference or a const reference?
a b c always means a (b c) as is
right associative, it is a rvalue. We can write
(ab)c, depending what ab returns.
int i5, j4 (ij)3 // lvalue,
return the new i cout ltlt iltlt j // get 3 4
(i3)4 // lvalue, return the new i
cout ltlt iltlt j // get 4 4 i j 3
// get 3 3
COMP152
51
52
  • We cannot write (a b) c if we return a const
    ref
  • const T operator(const T)
  • We can do (ab)c if we return a non-constant
    ref
  • T operator(const T)

It can be both a l-value and r-value!
COMP152
52
53
Summary on overloading
  • class T
  • ...
  • public
  • ...
  • T operator(const T right)
  • ...
  • T Toperator(const T right)
  • if (this right) return this
  • return this
  • main()
  • T a,b

1. Const reference for the argument (a
r-value) 2. Return a reference to the left-hand
side (a l-value), and this is converted into a
reference 3. Check for self-assignment
53
54
Function Value Return
  • The semantics of function value return are
    identical to those of initialization (like the
    semantics of argument passing)
  • A return is to initialize an un-named variable
    of the returned type.
  • The type of a return expression is checked
    against the type of the returned type, and all
    standard and user-defined type conversions are
    performed.

double f() return 1 // 1 is implicitly
converted into double(1) int fp() int
local1 return local // bad! int fr()
int local1 return local // bad!
COMP152
54
55
X f() X x return x
return x returns a temporay object temp of
class X by constructor (because x is a local
object, and to be lost!)
COMP152
55
56
include ltiostreamgt using namespace std class
X public X() cout ltlt "constructor\n"
X(const X x)cout ltlt "copy constructor\n"
// return an object of X X f() X x
return x // must be rvalue const X cf() X
x return x // must be rvalue const X
crf(X x) return x //can be rvalue or
lvalue X rf(X x) return x
int main() X x,y f() x // No
compilation error but does nothing f cf()
// cfx() x is error f rf( y ) f
crf( y ) // crfx( y ) x is error return
0
constructor (for X x in main) constructor (for X
y in main) constructor (for X x in f) copy
constructor (Unix has that, but not Linux, for
return x in f) constructor (for X x in cf) copy
constructor (Unix has that, but not Linux, for
return x in cf)
COMP152
56
57
  • A function can return
  • an object, a constant object,
  • a reference to an object, and a constant
    reference to an object
  • Returning an object or constant object may call
    the copy constructor to copy the returned value
    to some temporary object
  • Compiler dependent the compiler may do some
    optimization on function return so as to minimize
    calling copy constructor
  • Returning a reference or a constant reference
    does NOT call the copy constructor
  • More efficient
  • However, remember NOT to return a local variable
    in your function as a non-constant reference!
  • Good practice
  • to return a functions local variable, use return
    by value or return by constant value.
  • to return non-local objects, use return by
    reference or constant reference.

COMP152
57
58
Assign objects of different classes
  • class T
  • ...
  • public
  • ...
  • T operator(const T right)
  • T operator(const X right)
  • T operator(const int right)
  • ...
  • main()
  • T a,b
  • X c,d
  • b a // b.operator(a)

58
59
Input/output
  • class T
  • ...
  • ostream operatorltlt(ostream out, const T t)
  • return out
  • istream operatorgtgt(istream in, T t)
  • return in
  • main()
  • T a

Before, we wrote a display or print function.
59
60
Which operators to overload?
  • Only those for which it makes sense
  • and for which there is a genuine need
  • and which the users will expect
  • Typically these are usually appropriate
  • ltlt
  • gtgt
  • If the class involves arithmetic type (e.g.
    complex, rational, vector, matrix, ), arithmetic
    operations should be provided.

60
61
Essential operators
class X X() X(const X) X() X
operator(const X) ostream
operatorltlt(ostream out, const X x)
62
Midterm preparation
  • No templates
  • Programming questions, no multiple choice
    questions
  • One A4 paper with notes written or typed on both
    sides
  • No calculators or other devices
  • Check last midterm

63
  • Operator overloading part II

64
Using Operators on Class Objects
  • Overloading provides concise and intuitve
    notation
  • object2 object1.add(object2) vs. object2
    object1 object2
  • The operators must be overloaded for that class
  • Default operations
  • Assignment operator ()
  • Member-wise assignment between objects
  • Address operator ()
  • returns address of object
  • Comma operator (,)
  • evaluates expression to its left then the
    expression to its right
  • Can be overloaded/overruled by the programmer

COMP152
64
65
Restrictions on Operator Overloading
  • Cannot change
  • Precedence of operator (order of evaluation)
  • Use parentheses to force order of operators
  • Associativity (left-to-right or right-to-left)
  • 234 (64) vs. 232 (29)
  • Number of operands
  • e.g., !, or is unary, i.e., can only act on
    one operand as in i or ptr
  • How operators act on built-in/primitive data
    types (i.e., cannot change integer addition)
  • Cannot create new operators
  • Remember, static functions only access static
    data
  • Operators must be overloaded explicitly
  • Overloading and does not overload

COMP152
65
66
Restrictions on Operator Overloading
Operators that can be overloaded Operators that can be overloaded Operators that can be overloaded Operators that can be overloaded Operators that can be overloaded Operators that can be overloaded Operators that can be overloaded Operators that can be overloaded
- /
! lt gt -
/ ltlt gtgt gtgt
ltlt ! lt gt
-- -gt , -gt () new delete
new delete
Operators that cannot be overloaded Operators that cannot be overloaded Operators that cannot be overloaded Operators that cannot be overloaded Operators that cannot be overloaded Operators that cannot be overloaded Operators that cannot be overloaded Operators that cannot be overloaded
. . ?
Member functions declaration bool
operator!() const bool operator(const T)
const bool operatorlt(const T) const
bool operator!(const T right) const bool
operatorgt( const T right) const bool
operatorlt(const T right) const bool
operatorgt(const T right) const
COMP152
66
67
Operators as Class Members
  • Leftmost object must be of the same class as
    operator function
  • Use this keyword to explicitly get left operand
    argument
  • Operators (), , -gt or some other assignment
    operator must be overloaded as a class member
    function
  • Called when
  • Left operand of binary operator is of this class
  • Single operand of unary operator is of this class

COMP152
67
68
// subscript operator can be both modifiable
lvalue and rvalue T operator(int) //
return the object at the index //
subscript operator if you only want it to be an
rvalue T operator(int) const // constant
member function cannot be lvalue
// May also be // const
T operator(int) const
// but NOT // T operator(int)
const // (compile error) T
operator()(int, int 0) const // at most 2
parameters
  • The const matters, and is part of the
    prototype,
  • We call it const overloading (the prototypes
    above)
  • The compiler decides based on the type of the
    calling object.
  • If it is const object, the const member function
    will be used. Sometimes we need this if we want
    to use a different member function for a const
    object.
  • If it is not a const object, the non-const
    function will be used, no matter whether it is a
    rvalue or lvalue

COMP152
68
69
include ltiostreamgt using namespace std class B
public const int operator(int i) const
cout ltlt "Constant function is called" ltlt
endl return datai int
operator(int i) cout ltlt "Non-constant
function is called" ltlt endl return datai
private int data10 int main() B
b1 const B bc b1 b10 b12
bc2 cout ltlt bc1 ltlt endl return 0
Non-constant function is called (for
b10) Non-constant function is called (for
b12) Constant function is called (for
bc2) Constant function is called (for
bc1) 0
COMP152
69
70
Operators as Global Functions
  • Need parameters for both operands
  • Can have object of different class
  • Can be a friend to access private or protected
    data
  • Both ltlt and gtgt must be global functions
  • Cannot be class members
  • Overloaded ltlt operator
  • Left operand is of type ostream
  • Such as cout object in cout ltlt classObject
  • Similarly, overloaded gtgt has left operand of
    istream
  • Such as cin object in cin gtgt classObject

COMP152
70
71
Global Functions Commutative Operators
  • May want to be commutative
  • So both a b and b a work
  • Suppose we have two different classes
  • If the overloaded operator is a member function,
    then its class is on left
  • HugeIntClass long int
  • Can be member function for HugeIntClass
  • HugeIntClass HugeIntClass
  • Can be member function as well
  • long int HugeIntClass
  • For this to work, needs to be a global
    overloaded function

HugeInt operator( long, HugeInt ) //
function overloading HugeInt operator(
HugeInt, long ) HugeInt operator( HugeInt,
HugeInt )
COMP152
71
72
Overloading Unary Operators
  • Can overload as member function with no arguments
  • Can overload as global function with one argument
  • Argument must be class object or reference to
    class object
  • If member function, needs no arguments
  • bool operator!() const
  • If global function, needs one argument
  • bool operator!( const T ), i.e., !f becomes
    operator!(f)

COMP152
72
73
Overloading Binary Operators
  • Member function one argument
  • const T operator(const T)
  • s1 s2 // a string
  • s1 s2 s3 // same as s1 ( s2 s3 )
  • (s1 s2) s3 // compiler yells
  • Global function two arguments
  • One of the arguments must be class object or
    reference
  • const T operator(T, const T)
  • // no const for the first argument
  • y z becomes operator( y, z )
  • Note that int type provides a variant of lvalue

int i2,j4 (j i) 2 // return the new
j cout ltlt i ltlt j // output 2 8
COMP152
73
74
Case Study String Class
  • Build class String
  • String creation, manipulation
  • Similar to class string in standard library
  • Conversion constructor
  • Any single-argument constructor
  • Turns objects of other types into class objects
  • Example String s1( "happy" )
  • Creates a String from a char
  • Overloading function call operator
  • String.h, String.cpp, stringtester.cpp

COMP152
74
75
stringtester.cpp Sample Output (1/3)
Conversion (and default) constructor
happy Conversion (and default) constructor
birthday Conversion (and default) constructor s1
is "happy" s2 is " birthday" s3 is "" The
results of comparing s2 and s1 s2 s1 yields
false s2 ! s1 yields true s2 gt s1 yields
false s2 lt s1 yields true s2 gt s1 yields
false s2 lt s1 yields true Testing !s3 s3 is
empty assigning s1 to s3 operator called s3 is
"happy" s1 s1 s2 yields s1 happy
birthdayhappy birthday
COMP152
75
76
stringtester.cpp Sample Output (2/3)
s1 " to you" yields Conversion (and default)
constructor to you Destructor to you s1
happy birthdayhappy birthday to you Conversion
(and default) constructor happy birthday Copy
constructor happy birthday Destructor happy
birthday The substring of s1 starting at location
0 for 14 characters, s1(0, 14), is happy
birthday Destructor happy birthday Conversion
(and default) constructor appy birthday to
you Copy constructor appy birthday to
you Destructor appy birthday to you The
substring of s1 starting at location 15, s1(15),
is appy birthday to you
The constructor and destructor are called for the
temporary String
COMP152
76
77
stringtester.cpp Sample Output (3/3)
Destructor appy birthday to you Copy
constructor happy birthdayhappy birthday to
you s4Ptr happy birthdayhappy birthday to
you Assigning s4Ptr to s4Ptr operator
called Attempted assignment of a String to
itself s4Ptr happy birthdayhappy birthday to
you Destructor happy birthdayhappy birthday to
you s1 after s10 'H' and s16 'B' is
Happy Birthdayhappy birthday to you Attempt to
assign 'd' to s130 yields Destructor
happy Destructor birthday Destructor Happy
Birthdayhappy birthday td you
COMP152
77
78
Overloading and --
  • Increment/decrement operators can be overloaded
  • Prefix increment x
  • Postfix increment x
  • Suppose we want to add 1 to a Date object d1
  • Member-function prototype for prefix increment
  • Date operator() // return a reference for
  • // successive operation
    yx
  • d1 becomes d1.operator()
  • Global-function prototype for prefix increment
  • Date operator( Date )
  • d1 becomes operator( d1 )

COMP152
78
79
Postfix Increments
  • Postfix increment has a dummy integer parameter
  • d
  • An int with value 0
  • Overload operator with different function
    parameters
  • Member-function prototype for postfix increment
  • T operator( int ) // must be rvalue
  • d1 becomes d1.operator(0)
  • The value returned is a temporary variable inside
    the function, i.e., it does not and cannot return
    a reference
  • Can NOT use d to increment d twice (because
    it is the temporary variable returned, not the
    incremented object)
  • y d will have y equal to d2.
  • Global-function prototype for postfix increment
  • T operator( T, int )
  • d1 becomes operator( d1, 0 )

COMP152
79
80
Overloading and --
Date operator() // prefix increment
operator, Date Date operator( int ) //
postfix increment operator, Date
  • Return values
  • Prefix increment (x)
  • Increment and then return the incremented object
  • Return by reference (Date ) so that we can use
    x to increment x twice
  • Theoretically can be a lvalue (i.e., can be
    assigned like x 4), though we almost never
    use it as lvalue
  • Note that y x assigns y the value of x, NOT
    making y an alias of x!
  • Postfix increment (x)
  • Store x in a temporary object, increment x, and
    then return the temporary object
  • Returns by value (Returns temporary object with
    the objects old value)
  • Must be rvalue (cannot be on left side of
    assignment), e.g., y x // not x4
  • All this applies to decrement operators as well

COMP152
80
81
Case Study A Date Class
  • Overloaded increment operator
  • Change day, month and year
  • Function to test for leap years
  • Function to determine if a day is last of month
  • Date.h, Date.cpp, datetester.cpp

COMP152
81
82
Date.h
class Date friend ostream operatorltlt(
ostream, const Date ) public // default
constructor Date( int m 1, int d 1, int y
1900 ) void setDate( int, int, int ) //
set month, day, year Date operator() //
prefix increment operator, Date Date
operator( int ) // postfix increment operator,
Date const Date operator( int ) // add
days, modify object bool leapYear( int )
const // is date in a leap year? bool
endOfMonth( int ) const // is date at the end of
month? private int month int day int
year static const int days // static
member variable array of days per month void
helpIncrement() // utility function incrementing
date // end class Date
Note the difference between prefix and postfix
increment
COMP152
82
83
Date.cpp (1/5)
include "Date.h" // initialize static member at
file scope one classwide copy const int
Datedays 0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 // Date
constructor DateDate( int m, int d, int y )
setDate( m, d, y ) // end Date
constructor // set month, day and year void
DatesetDate( int mm, int dd, int yy )
month ( mm gt 1 mm lt 12 ) ? mm 1 year
( yy gt 1900 yy lt 2100 ) ? yy 1900
// test for a leap year if ( month 2
leapYear( year ) ) day ( dd gt 1 dd lt
29 ) ? dd 1 else day ( dd gt 1
dd lt days month ) ? dd 1 // end function
setDate
COMP152
83
84
Date.cpp (2/5)
// overloaded prefix increment operator Date
Dateoperator() helpIncrement() //
increment date return this // reference
return to create an lvalue // end function
operator // overloaded postfix increment
operator note that the // dummy integer
parameter does not have a parameter name Date
Dateoperator( int ) Date temp this
// hold current state of object
helpIncrement() // return unincremented,
saved, temporary object return temp // value
return not a reference return // end function
operator
Postfix increment updates object and returns a
copy of the original
Do not return a reference to temp, because
returning a reference may make the variable a
lvalue. Since temp is a local variable, it will
be destroyed leading to access error
COMP152
84
85
Date.cpp (3/5)
// add specified number of days to date const
Date Dateoperator( int additionalDays )
for ( int i 0 i lt additionalDays i )
helpIncrement() return this // enables
cascading // end function operator // if the
year is a leap year, return true otherwise,
return false bool DateleapYear( int testYear )
const if ( testYear 400 0 (testYear
100 ! 0 testYear 4 0) ) return
true // a leap year else return false
// not a leap year // end function leapYear //
determine whether the day is the last day of the
month bool DateendOfMonth( int testDay ) const
if ( month 2 leapYear( year ) )
return testDay 29 // last day of Feb. in leap
year else return testDay days month
// end function endOfMonth
COMP152
85
86
Date.cpp (4/5)
// function to help increment the date void
DatehelpIncrement() // day is not end of
month if ( !endOfMonth( day ) ) day
// increment day else if ( month lt 12 )
// day is end of month and month lt 12
month // increment month day
1 // first day of new month // end if
else // last day of year
year // increment year month 1 //
first month of new year day 1 //
first day of new month // end else //
end function helpIncrement
COMP152
86
87
Date.cpp (5/5)
// overloaded output operator ostream
operatorltlt( ostream output, const Date d )
static char monthName 13 "", "January",
"February", "March", "April", "May",
"June", "July", "August", "September",
"October", "November", "December" output ltlt
monthName d.month ltlt ' ' ltlt d.day ltlt ", " ltlt
d.year return output // enables cascading
// end function operatorltlt
COMP152
87
88
datetester.cpp
Date d1 // defaults to January 1, 1900 Date d2(
12, 27, 1992 ) // December 27, 1992 Date d3( 0,
99, 8045 ) // invalid date cout ltlt "d1 is " ltlt
d1 ltlt "\nd2 is " ltlt d2 ltlt "\nd3 is " ltlt d3 cout
ltlt "\n\nd2 7 is " ltlt ( d2 7 ) d3.setDate(
2, 28, 1992 ) cout ltlt "\n\n d3 is " ltlt d3 cout
ltlt "\nd3 is " ltlt d3 ltlt " (leap year allows
29th)" Date d4( 7, 13, 2002 ) cout ltlt
"\n\nTesting the prefix increment operator\n
ltlt " d4 is " ltlt d4 ltlt endl cout ltlt "d4 is "
ltlt d4 ltlt endl cout ltlt " d4 is " ltlt d4 cout
ltlt "\n\nTesting the postfix increment
operator\n ltlt " d4 is " ltlt d4 ltlt
endl cout ltlt "d4 is " ltlt d4 ltlt endl cout ltlt
" d4 is " ltlt d4 ltlt endl
Demonstrate prefix increment
Demonstrate postfix increment
COMP152
88
89
datetester.cpp Sample Output
d1 is January 1, 1900 d2 is December 27, 1992 d3
is January 1, 1900 d2 7 is January 3, 1993
d3 is February 28, 1992 d3 is February 29,
1992 (leap year allows 29th) Testing the prefix
increment operator d4 is July 13, 2002 d4 is
July 14, 2002 d4 is July 14, 2002 Testing the
postfix increment operator d4 is July 14,
2002 d4 is July 14, 2002 d4 is July 15, 2002
COMP152
89
90
Casting explicit type conversion
  • Castingstatic_castltTgt x
  • i static_castltintgt d
  • Function-style cast T(x)
  • it calls the constructor, but equivalent to
    static_cast for built-in types
  • i int(d)
  • Old C style (T) x
  • i (int) d

COMP152
90
91
Convert a primitive type to a class
  • Use constructors
  • t T(i)
  • how to do if T is a primitive type for an object
    of class X? int(x)?
  • Overload the assignment
  • t i
  • T operator(int i)

COMP152
91
92
Conversion operator from X to T
class X operator T() const Xoperator
T() const X x T t t x // t T(x)
// t x.T()
93
Example
  • Prototype
  • Aoperator char() const
  • Casts class A to a temporary char
  • static_castltchargt(s) calls s.char()
  • Same as (char) s
  • static_castltfloatgt(obj) calls obj.float()
  • Same as (float)obj
  • Casting can sometimes prevent the need for
    overloading
  • Suppose class String can be cast to char
  • cout ltlt s // s is a String Compiler implicitly
    converts s to char for output
  • Do not have to overload ltlt

COMP152
93
94
include ltiostreamgt include ltstringgt using
namespace std class record // 1 to 1 mapping
between key and record public record(string
str "") name str key str.size()
operator int() const // no return
type for implicit casting to compare records
return key private int key //
search key of the string string name // and
some other fields if necessary int main()
record r1 record r2("COMP") record
r3("152") int k cout ltlt r1 ltlt endl //
implicit cast r1 to int k r2
// implicit casting cout ltlt k ltlt endl if(
r3 lt k ) // casting r3 to int cout ltlt "r3 lt
k\n" return 1
0 4 r3 lt k
COMP152
94
95
How to hide an operator?
class X private void operator(const
X) void operator() void operator,(const
X) Void f(X a, X b) ab // error
operator private a // error operator
private a,b // error operator, private
Write a Comment
User Comments (0)
About PowerShow.com