Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

CS 246 Notes

Download as pdf or txt
Download as pdf or txt
You are on page 1of 38

University Of Waterloo

CS-246

Object-Oriented Programming

Edited By Yiming, Dai © at Github


Last Revision: December 26, 2019

Table of Contents
IO redirection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Wildcard Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
pipe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Output as arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
egrep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
File Permission . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Shell Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Shell scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Function Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
New Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Dynamic Memory Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Return by value, pointer, or reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Operator Overloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Separate Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Include Guard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
C++ Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Default/Zero Parameter Ctors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Big 5 cont. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Arrays / const methods / invariants / encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Iterator Design Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Range-Based For Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Finish Accessors/Mutators System Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
UML(Unified Modelling Language) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Inheritance, Virtual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Method Overriding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Destructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Virtual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
C++ Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Observer Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Design Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Iterator Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Factory Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Template Method Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Public Virtual Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Visitor Design Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34


Book Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
STL std::map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Compilation Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Reduce Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

2
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Object-Oriented Programming Fall 2019

Chapter 01 - Linux Shell


Professor: Nomair Author: Yiming Dai

> Shell is program to interface with an OS

> Graphical Shells

+ intuitive/easy to learn
- inflexible

> Command Line Shell

+ modules/flexible
- you get a command prompt where you type commands
- steep learning curve

> Linux File System

– files that can contain after files are called directories;


– files are organized in a tree structure;

> Path is the location of a file in the file system;

> ls - listing of non-hidden files with formatted display (i.e. more spaces between names);

> Hidden files in Linux - name begins with a .

> pwd - present working directory;

> Special Directory

– . => current directory


– .. => parent directory
– ../.. => grandparent directory
– ~ => home directory
– - => back to last directory
– ~userid => user’s home directory

> cat(concatenated) => display a text file

> [Ctrl + C] => kill the program

> [Ctrl + D] => send End Of File signal

> man => show the manual of the command

3
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

IO redirection

> Output Redirection


– cat > output.txt => Output redirection to a text file [May overwrite]
– cat ≫ output.txt => Output redirection to append words to a text file
> Input Redirection
– cat input.txt => cat Open file => Read => Display
– cat < input.txt => Shell not cat to Open file => Read => Send content directly to cat => Display
> cat -n < sample.txt > tmp.txt => Input/Output redirection
> myprog < in.txt > out.txt 2> err.log => Order does not matter
> myprog > out.txt 2>&1 => Connects stdout with stderr to be out.txt
> &1 => First output stream
> myprog 2>&1 > out.txt
> Every program has 3 streams
– Standard Input = stdin => default: keyboard | Use < to change to file
– Standard Output = stdout => default: screen | Use > to change to file
– Standard Error = stderr => default: screen | Use 2> to change to file

Wildcard Matching

> prog1 | prog2 => prog1 > temp and prog2 < temp
– ls *.txt => match any file end with .txt [Shell intercepts the Globbing Pattern, and substitutes the
globbing pattern with filename that matches]
> Linux pipe | connects stdout of prog1 to stdin of prog2
stdin stdout => stdin stdout + stderr
Start Program 1 Program 2 Stop

pipe

> prog1 2> err.log | prog2 2≫ err.log => Input redirection errors of two progs

Example.
Q: Count number of words in the first 20 lines in sample.txt
A: head -20 sample.txt | wc -w

Example.
Q: Suppose files words1.txt words2.txt etc. contain lists of words, 1 per line. Print a duplicate free list of
words in words*.txt
A: cat words*.txt | sort | uniq

4
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Output as arguments

> Use $(⋯) to embed a command within another command

> echo "Today is $(data) and I am $(whoami)" => Single argument (MUST double quote)

> echo Today is $(date) and I am $(whoami) => Multiple arguments

> Use double quptes to indicate an argument that contains space

> Single quotes will suppress embed commands

egrep

> grep -E = egrep => egrep pattern files

> egrep goes line by line to match pattern;

> egrep "cs246 | CS246" = egrep "(cs|CS)246" ≠ egrep "(c|C)(s|S)246 = egrep [cC][sS]246

> Use \ to escape any characters with special meaning;

> [abc] ≡ (a|b|c) => choose a single charfrom set

> [^abc] => choose one char NOT in set

> ? => 0 or 1 occurence of preceeding subexpression

> * => 0 or more occurence of preceeding subexpression

> + => 1 or more occurence of preceeding subexpression

> . => any one character

> .* => 0 or more characters

> cs.*246 or .*cs.*246.* => output lines containing a substring cs followed by 0 or more chars followed by 246

> ^cs.*246 => force the line to start with c

> cs.*246$ => force the line to end with 6

> egrep "^(..)*$"

> ls -a | egrep "^[^a]*a[^a]*$ => list all files in current directory whose name contains exactly one a

File Permission

> When use command ls -l

– the first position is ordinary file => d if directory; - if file


– followed by three groups (user, group, other, all)
– operate with +|–|= => notice that = may have implicit operation

5
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Shell Variables

> x=1 => all shell variables are strings (no spaces between)

> echo $x => echo $x

> $PATH => a list of directory paths system used to search commands separated by :

> PATH=$PATH:/bin => Add /bin to $PATH (String Concatenation)

Shell scripts

> Text files that contain bash commands executed as a program

> File: newscript


1 vi newscript # New script
2 # !/ bin / bash
3 ls
4 whoami
5 date
6 pwd
7 # Exit vim
8 # Notice that default permission is r + w
9 chmod u + x newscript
10 # But current directory may not in $PATH , i . e . OS cannot find command newscript
11 ./ newscript # Run commands inside the file

> Command Line Arguments => ./newscript as $0 | arg1 as $1

> File: isItAWord


1 vi isItAWord
2 # !/ bin / bash
3 egrep " ^ $1$ " / usr / share / sict / words
4 # Exit vim
5 ./ isItAWord ( word )

> Single quotes suppress variables

> File goodPassword


1 vi goodPassword
2 # !/ bin / bash
3 # Answer whether a word is in the dictionary = > not a good password
4
5 egrep " ^ $1$ " / usr / share / dict / words > / dev / null
6
7 # Method 1
8 if [ $ ? - eq 0 ]; then
9 echo Not a good password
10 else
11 echo Maybe a good password
12 fi
13

6
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

14 # Method 2
15 if [ $ ? - eq 0 ]; then
16 echo Not a good password
17 elif [ $ ? - ne 0 ]; then
18 echo Maybe a good password

> Linux process sets/returns a status code of last executed command (hidden as $?)

> echo $? => Status code 0 if success

> test 1 -eq 2 or [ 1 -eq 2] => test if 1 equals to 2, answer saved in $?

> Spaces need to be set between commands and arguments

> File: goodPassword (Upgraded)


1 vi goodPassword
2 # !/ bin / bash
3 # Answer whether a word is in the dictionary = > not a good password
4
5 usage () {
6 echo " Usage : $0 password " >&2
7 exit 1
8 }
9
10 if [ $ { # } - ne 1 ]; then
11 usage
12 fi
13
14 egrep " ^ $1$ " / usr / share / dict / words > / dev / null
15
16 # Method 1
17 if [ $ ? - eq 0 ]; then
18 echo Not a good password
19 else
20 echo Maybe a good password
21 fi

> File: Count


1 # !/ bin / bash
2 # count limit = > counts the numbers from 1 to the limit
3
4 usage () {
5 echo " Usage $0 limit " 1 >&2
6 echo " where limit is at least 1 " 1 >&2
7 exit 1
8 }
9
10 if [ $ # - ne 1 ]; then
11 usage
12 fi
13
14 if [ $1 - lt 1 ]; then
15 usage

7
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

16 fi
17
18 x =1
19 while [ $x - le limit ]; do
20 echo $1
21 x = $ (( x + 1) )
22 done

> $((x + 1)) => treat x as arithmetic argument and do arithmetic operation instead of string concatenation

> File: group rename files


1 # !/ bin / bash
2 # rename all . c files to . cc
3
4 # Examples of " for "
5 # for filename in $ ( ls ) ; do echo $filename ; done = > print all files in current ↩
directory
6 # for filename in add *; do echo $filename ; done = > print all files start with ↩
add in current directory
7
8 for name in *. c ; do
9 mv $ { name } $ { name % c } cc
10 done

> Double quotes make a content to a single argumetn like a single stirng

8
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Object-Oriented Programming Fall 2019

Chapter 02 - C++
Professor: Nomair Author: Yiming Dai

I/O

> When we include iostream we can produce output;


1 std :: cout << data1 << data2 ;
2 std :: cout << std :: endl

> When we use ‘using namespace std’, we cannot use our own defined ‘cout’
> Compile using g++ -std=c++14 hello.cc -o myprog (-o means executable)
> When we include iostream we are able to access 3 global variables
i. std::cout (struct ostream) => connects to stdout with output operators cout ≪ ⋯
ii. std::cerr (struct ostream) => connects to stderr with output operators cerr ≪ ⋯
iii. std::cin (struct istream) => connects to stdin with input operators cerr ≫ ⋯
> File: Plus.cc => Reads 2 ints and prints the result of addition
1 # include < iostream >
2 using namespace std ;
3
4 int main () {
5 int x , y ;
6 cin >> x >> y ;
7 cout << x + y << endl ;
8 }

> cin will read from the first non-whitespace char until it hits a whitespace
> When reading from input, it’s a good idea to check if a read successful
> If a read fails, the expression cin.fail() is going to be true
> If a read fails due to EOF, cin.fail() and cin.eof() are to be true
> File: io/readInts.cc => Read all ints from stdin and echo one per line to stdout. Stop if a read fails
1 # include < iostream >
2 using namespace std ;
3
4 int main () {
5 int i ;
6 while ( true ) {
7 cin >> i ;
8 if ( cin . fail () ) break ;
9 cout << i << endl ;
10 }
11 }

9
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

> C++ defines an automatic conversion from istream (type for cin) to bool;

> cin is treated as true if the last read succeeded, false otherwise;

> File: io/readInts_final.cc


1 # include < iostream >
2 using namespace std ;
3
4 int main () {
5 int i ;
6 while ( cin >> i ) {
7 cout << i << endl ;
8 }
9 }

> If a read fails, all subsequent reads fail * (unless you ackowledge the failure)

> File: io/readInts_err_check.cc


1 # include < iostream >
2 using namespace std ;
3
4 int main () {
5 int i ;
6 while ( true ) {
7 if ( cin >> i ) cout << i << endl ;
8 else {
9 if ( cin . eof () ) break ;
10 else {
11 cin . clear () ;
12 cin . ignore () ;
13 }
14 }
15 }
16 }

> cin.ignore() => ignores one character at a time

String

> In C, we use characters arrays (null terminated) to represent strings;

> In C++, we use header <string>; Not a array;

C C++
Comparison strcmp ==, !=, <, >
Length strlen str.length();
Concatenation strcat(s1, s2) s1 = s1 + s2;
Character Access s[i] s[i]

> C++ use I/O manipulators as placeholders in C

10
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

1 int x = 95;
2 cout << x; // prints x in decimal
3 cout << hex << x ; // prints x in hexadecimal
4 cout << dec ; // back to default print option

> In A2, use iostream, iomanip, showpoint, setprecision(3), boolalpha

> EVerything we learnt about reading/writing from/to stdin/stdout applies to other sources of data.

> Anything you can do with istream variables (e.g. cin) you can do with an ifstream variables;

> Anything you can do with ostream variables (e.g. cout) you can do with an ofstream variables;

> Use <fstream> to read and write files

– ifstream => input file stream


– ofstream => output file stream

> The file is closed using ifstream when the variable goes out of scope (e.g. stack pop up)

> We can connect streams to strings;

> Use <sstream> to read in and write to a string by i/ostringstream

> Default Arguments


1 void printFile ( string file = " t . txt " ) {
2 // code
3 }
4 printFile ( " a . txt " ) ;
5 printFile () ; // default t . txt
6 # Default arguments must come last ;
7 # If we omit arguments , we must omit the last one

Function Overloading

> In C++ we write functions of same name as long as the numbers or types of arguments have a difference
1 # Legal in C ++ but not in C
2 int neg ( int x ) { return -x ; }
3 bool neg ( bool b ) { return ! b ; }
4 # cin >> a is equivalent to operator >> ( cin , a ) [ a is pass by reference ]

> If multiple functions with the same name appears, ‘func()’ will not be compiled;

> ‘const int *p = &n’ means p is a point to int which is a constant

New Syntax

11
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

1 struct Node {
2 int data ;
3 struct Node * next ;
4 };
5 Node n = {5 , NULL };
6
7 # Constants
8 const int * p = & n ;
9 p = & x ; [ Legal ]
10 * p = 5; [ Illegal ]
11
12 int * q = & n ;
13 * q = 2; [ Legal ]
14
15 int y = 42;
16 p = &y;
17 * p = 5; [ Illegal ]
18
19 int * const r = & n ; # r is a constant pointer to integer
20 r = & y ; [ Illegal ]
21 * r = 1; [ Legal ]
22
23 int const * p = & n ; # p is a pointer to a constant integer
Reference

1 int y = 10;
2 int & z = y ;
3 # z is an lvalue reference to y ; it acts like a const . ptr . to y ;
4 # A lvalue reference is a const . ptr . with [ automatic dereference ];
5 # which means no need to write ‘* z =15 ’ but rather ‘z =15 ’
6
7 int * q = & z ;
8 # above create a ptr . to the integer
9 # z acts like y ( a alias to y )
10 # thus size ( z ) = size ( y )
11
12 # Cannot create a reference to a reference
13 # Cannot create a ptr . to a reference but can create a reference to a ptr .
14 # Cannot create an array of reference
15 # References must be initialized ;
16 # References must be initialized to something with an address
17 int & z = 5; [ Illegal ]
18
19 # Lvalue is (1) a storage location and (2) something with an address
20 # Lvalue = > anything that can be written on the LHS of an assignment
21 # Rvalue = > anything not an lvalue | temp / computed value
22 void inc ( int & x ) {
23 x = x + 1;
24 }
25 int y = 5;
26 inc ( y ) ;
27 cout << y ; = > print 6
28

12
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

29 std :: istream & operator >> ( std :: istream & in , int & x ) ;
30 # return type is std :: istream since may need consecutive reading
31 # cin >> x >> y
32 $ streams cannot be copied
33
34 struct ReallyBig {};
35 void f ( ReallyBig rb ) ;
36 ReallyBig b = ___ ;
37 f ( b ) = > requires create huge stack frame or pass by value of b
38
39 # C ++ could pass by ptr . to avoid copy and pass by reference by below
40 void g ( ReallyBig & rb ) ;
41 g ( b ) ; = > within g , rb is another name for b
42 # changes made by g will be cisible outside g
43
44 void h ( const ReallyBig & rb ) ; = > no copy | h cannot modify the original
45 # Pass by reference to const whenever possible for anything bigger than an Int
Dynamic Memory Allocation

1 int * ptr = ( int *) malloc (10 * sizeof ( struct Node ) ) ;


2 free ( ptr ) ;
3 # C only works ( void *) pointers
4
5 # C ++ version = > new , delete , adn nullptr
6 int * ptr = new int ;
7 * ptr = 5;
8 int * p2 = new int {13};
9 delete ptr ;
10 delete p2 ;
11 # If delete a nullptr , does nothing
12
13 # Two dimensional array
14 int ** arr ;
15 arr = new int * [10];
16 for ( int i = 0; i < 10; ++ i ) {
17 arr [ i ] = new int [5];
18 }
19 for ( itn i = 0. i < 10; ++ i ) {
20 delete [] arr [ i ]; # Empty square bracket to delete all the elements but not only ↩
the first element in the address
21 }
22 delete [] arr ;
23 # If allocated using new ...[...] , delete using []
24 # Do not delete the same memory address twice
25 # Do not refer to already freed / out of scope addresses
26 # If you think you might be doing that , set it to nullptr to have a better chance of↩
catching the problem
Return by value, pointer, or reference

1 # Let ’s have a function to build nodes


2 Node getNode () { # returned value is an " rvalue "

13
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

3 Node n ; # being " copied " into " m " , but as of C ++11 , not actually this ↩
inefficient
4 return n ;
5 }
6 Node m = getNode () ;
7 # See more about move semantics versus copy semantics
8
9 # Better method below
10 Node * getNode () {
11 return new Node ; # Have to remember and free it
12 }
13 Node * ptr = getNode () ;
14 delete ptr ;
15 # If used ( Node &) same problem ; i . e . bound to variable that no longer exists
16
17 # Best way
18 Node & getNode () {
19 Node * ptr = new Node ;
20 return * ptr ;
21 }
22 Node & n = getNode () ;
23 delete & n ;
24
25 # Q : which to use ?
26 # A : return by value ; if can , since nto actually as expensive as it looks ( at least ↩
in C ++11 and up )
Operator Overloading

1 # I / O operators we have already seen use pass by ref . and return by ref .
2 cin . operator >> ( int )
3 std :: istream & operator >> ( std :: istream & in , int & i ) ;
4 std :: ostream & operator << ( std :: ostream & out , const int & i ) ;
5
6 std :: ostream & operator << ( std :: ostream & out , const Node * n ) {
7 if ( n != nullptr ) {
8 out << n - > value ;
9 }
10 return out ;
11 }
12 3 If not modifying the parameters , often want to return by value ;
Preprocessor

1 # define MAX 10 // Not type safe , use global constant instead ;

Tutorial

> ‘std::string str1;‘ is equivalent to ‘std::string str1 = ”;‘

> ‘using std::string;‘ => only use string part, better to debug;

14
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Separate Compilation

> Interface/headers (.h)

– type definitions
– function declarations

> Implementation (.cc)

– function defintions

> main.cc and vec.cc all include vec.h

> Never compiled .h files

> Never include a .cc file

> By default, the compiler compiles links and produces an executable file;

> To just compile g++ -c file.cc produces .o (object) files Object files contain

– compiled binary
– a list of things that were defined
– a list of things that were required

> Use a linker to merge object files g++ main.o a.o -o a.out

> Separate compilation allows us to only recompile files that have changed and then link everything

> Tools => /lectures/tools/make

> extern int global in abc.h and int global in abc.cc

Include Guard

> Prevents a header file from being included multiple times

> Every header file should have an include guard

C++ Classes

1 // student . h
2 # ifndef STUDENT_H
3 # define STUDENT_H
4 struct Student {
5 int assns , mt , final ;
6 float grade () ;
7 }
8 # endif
9
10 // student . cc
11 # include " student . h "
12 float Student :: grade () { // scope resolution = > " In the scope of "

15
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

13 return assns * 0.4 + mt * 0.2 + final * 0.4;


14 }
15
16 Student billy {80 , 50 , 70}; // must be constants
17 cout << billy . grade () << endl ;
> A class is any struct that can have functions;

> In C++ all structs are allowed to have functions, so they are all classes;

> An instance/value of a class is called an object;

> A function written inside a struct is called a members function => Method

> Calling a method requires an object of that class => within the method we have access to the fields of the
object on which we called the method

> Every method has a hidden parameter named this

i. this == &billy
ii. ∗this == billy

> C++ allows to write methods to construct objects => constructors (ctors)
18 struct Student {
19 Student ( int assns , int mt , int final ) ; // no return value
20 // constructors have the same name as the class
21 }
22
23 Student :: Student ( int assns , int mt , int final ) {
24 this - > assns = assns ;
25 this - > mt = mt ;
26 this - > final = final ;
27 }
28
29 Student billy {80 , 50 , 70};
30
31 Student * pBilly = new Student {80 , 50 , 70};
32 delete pBilly ;

> Advantages of ctors

– sanity check
– can overload
– default value for parameters

1 struct Student {
2 Student ( int assns = 0 , int mt = 0 , int final = 0) ;
3 }
4
5 Student :: Student ( int assns , int mt , int final ) {
6 this - > assns = assns < 0 ? 0 : assns ;
7 this - > mt = mt < 0 ? 0 : mt ;
8 this - > final = final < 0 ? 0 < final ;

16
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

9 }
10
11 Student s1 {80 , 45}; // final = 0;
12 Student s2 {}; // all are 0

Default/Zero Parameter Ctors

> Every class comes with a default ctor


1 struct Mystud {
2 int a ;
3 int * b ; // not initialized by default ctor
4 Student c ; // default ctor of Student is called by the default ctor of Mystud
5 }

> Rule 1: If we write our own ctor, we lose the default ctor
1 struct Vec {
2 int x ;
3 int y ;
4 Vec ( int , int ) ; // two integer value default to 0
5 }
6 // Valid = > Vec v {1 , 2};
7 // Invalid = > Vec v ; // no default ctor

> Initialize fields that are const/reference


1 int x ;
2 struct MyStruct {
3 const int y = x ;
4 int & z = x ;
5 }
6
7 struct Student {
8 const int id = 20233118;
9 }

> Steps for Object construction

i. Space is allocated
ii. Field initialization: call default ctors for fields that are objects
iii. Ctors body runs

> Let’s biject step 2 using Members initialization List (MIL)

– syntax available only in class


– can be used to initializing all/some fields
– MIL always initializes fields in declaration orders
– In some cases, using an MIL to initialize a field is more efficient than assigning it in the class body
– MIL has priority over in-class initialization

17
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

1 Student :: Student ( int id , int assns , int md , int final ) :


2 id { id } , assns { assns } , md [ md ] , final { final }{}
3
4 struct Vec {
5 int x = 0; // never used
6 int y = 0; // never used
7 Vec ( int x , int y ) ;
8 };
9
10 Vec :: Vec ( int x , int y ) : x { x } , y { y }{}
11
12 struct Bla {
13 Student s ;
14 Vec v ;
15 };
16
17 // Copying Ctors below
18
19 Student billy {80 , 50 , 70}
20 Student bobby { billy }

> Construct an object as a copy of an existing object

– We got one for free


– Copies fields of existing object into the new object

> Every class comes with

– default ctor (0 parameters)


– copy ctor
– destructor (dtor)
– copy assignment operator
– move ctor
– move assignment operator

> A copy ctor takes a reference of the existing object


1 Student :: Student ( const Student & others ) :
2 assns { others . assns } , md { others . md } , final { others . final }

> The free copy ctor might not always do the correct thing
1 struct Node {
2 int data ;
3 Node * next ;
4 Node ( int , Node *) ;
5 Node ( const Node &;)
6 };
7
8 Node :: Node ( int data , Node * Next ) : data { data } , next { next }{}
9 Node :; Node ( const Node & others ) : data { others . data } , next { others . next }{}
10 Node * np = new Node {1 , new Node {2 , new Node {3 , nullptr }}};

18
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

11 Node n1 {* np }; // calls copy ctor


12 Node * n2 = new Node {* np }; // copy ctor
13
14 // Above only copies the address = > wrong
15 // Below is correct
16
17 Node :: Node ( const Node & others ) :
18 data { others . data } ,
19 next { others . next ? new Node { others . next } : nullptr }
20 {}

> A copy tor is called

i. constructing obj. as a copy of an existing obj.


ii. passing an object by value
iii. returning an object by value
iv. The second is the reason why parameter to a copy ctor is a reference

1 Node :: Node ( int data ) : data { data } , next { nullptr }{}


2
3 // If use ’ explicit ’
4 Node n {4};
5 void foo ( Node ) ;
6 foo ( n ) ;
7
8 // else
9 Node n = 4;
10 foo (10)
11 // single param ctor create implicit / automatic conversions

Big 5 cont.

> Destructors
1 Node * np = new Node {1 , new Node {2 , nullptr }};

> every class comes with a dtor

– dtor calls dtors on fields that are objects


1 delete np ; // calls dtor on Node 1 , 2 , ... until nullptr
2
3 Node ::~ Node () {
4 delete next ; // deleting nullptr is safe
5 }

> Copy Assignment Operator


1 Student billy {80 , 50 , 70};
2 Student bobby { billy }; // copy ctor
3 Student jane {};
4 jane = billy ; // copy assignment operator
5 jane . operator = ( billy ) // operator is a method

19
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

> Sometimes the one we get free does not do the correct thing
1 Node n1 {} , n2 {} , n3 {};
2 n2 = n2 ; // n2 . operator = ( n1 ) ;
3
4 Node & Node :: operator =( const Node & others ) {
5 if ( this == & others ) return * this ; // 1.
6 data = others . data ;
7 delete next ; // 2.
8 next = others . next ? new Node {* others . next } : nullptr ;
9 return * this ; // return a reference
10 }
11
12 // 1. if new fails to allocate memory , next is not assigned ;
13 make next a dangling ptr ;
14 Self Assignment Check ;
15 Betles to delay deleting next until we know that new will not fail ;
16
17 // 2. next might already pointing to heap memory ;
18 n1 = n1 ; n1 . operator = ( n1 ) ;
19 // next and others . next are the same = > access a dangling ptr ;
20
21 // Optimized version below
22 Node & Node :: operator =( const Node & others ) {
23 if ( this == & others ) return * this ; // 1.
24 Node * temp = next ;
25 next = others . next ? new Node {* others . next } : nullptr ;
26 delete next ; // 2.
27 data = others . data ;
28 return * this ; // return a reference
29 }

> Copy & Swap Idiom


1 // node . h
2 struct Node {
3 //
4 //
5 void swap ( Node &) ;
6 Node & operator =( const Node &) ;
7 }
8
9 // node . cc
10 # include < utility >
11 void Node :: swap ( Node & others ) {
12 using std :: swap ;
13 swap ( data , others . data ) ;
14 swap ( next , others . next ) ;
15 }
16
17 Node & Node :: operator =( const Node & others ) {
18 Node tmp { others }; // copy ctor ( deep )
19 swap ( tmp ) ;
20 return * this ;
21 }

20
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

22
23 // rvalue / node . c
24 // 2 calls to Basic ctor
25 // 2 calls to copy ctor ( to copy argument )
26 Node n2 { return value };
27 // 2 more calls of copy ctor ( construct n2 as copy of return value )

> Move ctor


1 // C ++11 introduced rvalue reference &&
2 Node :: Node ( Node && other ) :
3 data { other . data } , next { other . next }{}
4 // A rvalue reference is a reference to a temporary ( a rvalue )
5 // If a move ctor is available , it is called whenever we are constructing an ↩
object from a rvalue
6 // If we implement any of the Big 5 ( copy ctor , copy operator = , dtor , move ↩
operator =) , you lose move ctor
7
8 // Move assignment operator ( move operator =)
9 Node & Node :: operator =( Node && other ) {
10 swap ( other ) ;
11 return * this ;
12 }

> Rule of 5: If you need to write a custom copy ctor, or copy operator=, or move ctor, or move operator=, then
you usually need write all;

> Copy/Move Elision => Under certian conditions, the compiler is allowed (not required) to avoid some
copy/move ctor calls(even if these have side effect)
1 Vec v = makeVec ()
2 // This would cause move / copy ctor to be called
3 // The compiler may directly construct the Vec in the space for Vec v
4
5 Void foo ( Vec v ) { };
6 foo ( makeVec () ) ;
7 // fno - elide - constructors

> Operator Overloading: Methods or standalone functions


1 n1 = n2 ; // n1 . operator =( n2 ) ;
2 Vec v1 {1 , 2}
3 Vec v2 {3 , 4}
4 Vec v = v1 + v2 ; // v1 . operator +( v2 ) ;
5 v = v1 * 5; // v1 . operator *(5) ;
6 v = 5 * v1 ; // 5. operator *( v1 ) ;
7
8 Vec Vec :: operator +( const Vec & other ) {
9 return Vec { x + other .x , y + oter . y }; // implicitly this - > x
10 }
11 Vec Vec :: operator *( const int k ) {
12 return Vec { x * k , y * k };
13 }
14 Vec Vec :: operator *( const int , const Vec &) ;

21
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

15 ostream & Vec :: operator < <( ostream & out ) {


16 out << x << " " << y ;
17 return out ;
18 }
19 v2 << ( v1 << cout ) ; // v1 . operator < <( cout ) ;
20 // cout << a << b ; I / O operators are implemented as standalone functions

Arrays / const methods / invariants / encapsulation

1 struct Vec {
2 int x , y ;
3 Vec ( int , int ) ;
4 }
5 // Want compile as default ctor gone
> Options:
1 // implement a default (0 param ctor )
2 // stack arrays : use C ’s array initializing syntax
3 Vec arr [2] = { Vec {1 ,2} , Vec {3 ,4}};
4 // Instead of array of objects , create array of pointers to object
5 Vec * arr [3];
6 Vec ** arr = new Vec *[3];
7 for ( ) {
8 delete arr [ i ];
9 }
10 delete [] arr ;

> Const Methods


1 struct Student {
2 int assn , mt , final ;
3 float grade () const {
4 return 0.4 * assn + 0.2 * mt + 0.4 * final ;
5 }
6 }
7
8 const Student billy {70 , 65 , 75};

> const object can only call methods that are const

> Invariants => some assumption/statement that must not be violated for program to function corectly

> We need to hide information/implementation to protect invariants


1 struct Node {
2 int data ,
3 Node * next ;
4 Node ( int , int ) ;
5 ~ Node () {
6 delete next ;
7 }
8 }
9

22
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

10 Node n2 {3 , nullptr };
11 // When n2 is out of scope , dtor will run automatically
12 // Cannot call delete below
13 Node n1 {4 , & n2 };

> Node() assumed next is either nullptr or a ptr to heap

> Encapsulation

i. treat objects as capsules (black box)


ii. interact through provided methods (interface)
iii. public/private labels (control content below label)
1 struct Vec {
2 // default public visibility
3 Vec ( int , int ) ;
4 private :
5 int x , y ;
6 public :
7 Vec operator +( const Vec &) ;
8 }

> Try make every fields in struct to be private

> Class => default visibility is private (Struct is public)


1 // Rewrite Vec above
2 Class Cec {
3 int x , y ;
4 public :
5 Vec ( int , int ) ;
6 Vec operator +( const Vec &) ;
7 }

> Node Invariant => wrap Node within a List class


1 // list . h
2 Class List {
3 struct Node ; // declare Node as private
4 Node * thelist = nullptr ;
5 public :
6 void addToFront ( int n ) ;
7 int ith ( int i ) ;
8 ~ List () ;
9 }
10
11 // list . cc
12 struct List :: Node {
13 // Nobody have access to here since struct Node is already a private struct in↩
List class , so we do not need to set fields to be private
14 int data ;
15 Node * next ;
16 Node ( int , Node *) ;
17 ~ Node () {

23
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

18 delete next ;
19 }
20 }
21
22 List ::~ List () {
23 delete thelist ;
24 }
25
26 void List :: addToFront ( int n ) {
27 thelist = new Node (n , thelist ) ;
28 }
29
30 int List :: ith ( int i ) {
31 Node * curr = thelist
32 for ( int j = 0; j < i ; ++ j , curr = curr - > next ) ;
33 return curr - > data ;
34 }

Iterator Design Pattern

> Good solution to common design problems

> Keep track of how much of teh list we have traversed


1 for ( int * p = arr ; p != arr + size ; ++ p ) {
2 ... * p ...
3 }

> We will create a new (Iterator) class that acts as a ptr into a list

> Iterator have access to Node

> To Do List

– A way to create a fresh Iterator to the start of list


– A way to represent on Iterator to the end of list
– Overload !=, ++(unitary), *(unitary)
1 Class List {
2 Struct Node {
3 ...
4 };
5 Node * thelist = nullptr ;
6 public :
7 Class Iterator {
8 Node * curr ;
9 public :
10 explicit Iterator ( Node * n ) : curr { n } {}
11 itn & operator *() {
12 return curr - > data ;
13 }
14 Iterator & operator ++() {
15 curr = curr - > next ;

24
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

16 return * this ;
17 }
18 bool operator !=( const Iterator & other ) {
19 return curr != other . curr ;
20 }
21 };
22 Iterator begin () {
23 return Iterator { thelist };
24 }
25 Iterator end () {
26 return Iterator { nullptr }; x
27 }
28 // prev . List Methods
29 };
30
31 // Client Code
32 itn main ( void ) {
33 List l ;
34 l . addToFront (3) ;
35 l . addToFront (2) ;
36 l . addToFront (1) ;
37 for ( List :: Iterator it = l . begin () ; it != l . end () ; ++ it ) {
38 cout << * it << endl ; // print 1 ,2 ,3
39 * it += 1; // change to 2 ,3 ,4
40 }
41 }

> C++ has built-in support/syntax for the Iterator Design Pattern
1 auto x = y ; // define x to be the same type as y
2
3 for ( auto i : l) {
4 cout << i << endl ; // i is int ( by value )
5 }
6 for ( auto & i : l) {
7 i += 1; // i is int & ( ref . to data fields )
8 }

Range-Based For Loops

> We can us e a range-based for loop for a class MyClass if

– MyClass has methods begin/end which return objects of a class, say Iter.
– Iter. must overload !=, *(unitary), ++(unitary prefix)
– To force clients to use begin/end, make Iterator ctor provide
– if we make it private, List::begin/List::end will lose access (private really implies no access)
– the Iterator class can declare List to be a friend
1 Class List {
2 ...
3 public :
4 Class Iterator {

25
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

5 Node * curr ;
6 explicit Iterator ( Node * n ) : curr { n } {}
7 friend class List ;
8 };
9 };

– Friendship break encapsulation, so make as fewer friends as possible!

Finish Accessors/Mutators System Modeling

> Keep fields private and provide accessors(getters) and mutators(setters) public

> Suppose a class has private fields and no accessors/mutators - want to implement the I/O operators => as
standalone functions
1 Class Vec {
2 int x , y ;
3 ...
4 friend ostream & operator < <( ostream & , const Vec &) ;
5 }

26
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Object-Oriented Programming Fall 2019

Chapter 03 - System Modeling


Professor: Nomair Author: Yiming Dai

> Identify the abstraction/entities/classes

> Interaction/relationship between classes

UML(Unified Modelling Language)

Inheritance, Virtual

> A desired class inherits all members from the base class

> A desired class cannot access private inherited members


1 Class Book {
2 string title , author ;
3 int numPages ;
4 public :
5 Book ( string , string int ) ;
6 }
7
8 Class Comic : public Book {
9 string hero ;
10 public :
11 }
12
13 Class Text : public Book {
14 string topic ;
15 public :
16 }

1 Text :: Text ( string t , string a , int n , string topic ) :


2 title { t } , author { a } , numPages { n } , topic { topic } {}

> Above won’t work

– inherited fields were private


– MIL can only use fields declared by the class
– No default ctor for Book

> 4 steps to object construction

– space is allocated
– superclass part is constructed
– subclass fields constructed
– ctor body runs

27
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

1 Text :: Text ( string t , string a , int n , string topic ) :


2 Book {t , a , n } , topic { topic } {}

> protected => if a member is "protected" it is accessible by the class and its subclasses
1 Class Book {
2 protected :
3 string title , author ;
4 int numPages ;
5 public :
6 Book ( string , string int ) ;
7 }
8
9 Class Comic : public Book {
10 string hero ;
11 public :
12 }
13
14 Class Text : public Book {
15 string topic ;
16 public :
17 }
18
19 void Text :: addAuthor ( string a ) {
20 author += a ; // OK as author is protected
21 }
22
23 int main () {
24 Text t = ...
25 t . author = X // no access !
26 }

> Advice

– Keep fields private


– provide protected accessors/mutators

Method Overriding

1 Book b = Comic { , , 40 , " batman " }; // Cause slicing


2 b . isHeavy () ; // Call Book ’s copy ctor
3 // Book :: isHeavy () = > false // Call this !
4 // Comic :: isHeavy () = > true // Not call this !
> Using superclass pbs, to point to subclass objects will not cause slicing

> By default, compiler looks at the declared type of the ptr. to choose which method to run (static dispatch)

> We typically want the method to be chosen based on the type of object => use virtual keyword

> Virtual Method => the choice of method is based on the runtime type of the object (Dynamic Dispatch) but
more costly than static dispatch

> Polymorphism => the ability to accommodate multiple types within one abstraction

28
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

Destructor

> 4 steps to destroying objects

– subclass dtor runs


– dtor for subclass fields that are objects
– superclass dtor runs
– space is reclaimed

Virtual

> Superclass do not know the existence of subclasses, so

i. If a class might have subclasses, make the dtor virtual in the base class
ii. If a class will never have a subclass, declare it as final

1 class X {
2 virtual ~ X () {...}
3 }
4 class Y : public X {
5 ~ Y () {...}
6 }
7 class Z final : public X {
8
9 }

> Student::fees() has no implementation since

i. We don’t want to implemented it


ii. make it Pure Virtual (P.V.)

1 class Student {
2 public :
3 virtual int fees () = 0; // Pure Virtual Method = > No implementation
4 }

> Virtual: subclasses may override behaviour

> P.V.: subclasses must implement mrthod to be CONCRETE

> Student has a P.V. method

i. it is incomplete
ii. it is an ABSTRACT class

> A class is abstract if

i. it declares a P.V. method


ii. it inherits P.V. methods that it does not implement

> A class is concrete if it is not abstract

29
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

> Cannot create objects of an abstract class

> Abstract Classes

i. organize subclasses
ii. members (fields/methods) that are common across all subclasses can be placed in the base class
iii. act as an interface
iv. Polymorphism

> Virtual/P.V. - italics

> abstract class - class name in italics

C++ Template

> C++ template class is a class parameterized on type


33 template < typename T >
34 class Stack {
35 int len ;
36 int cap ;
37 T * contents ;
38 public :
39 void push ( T ) ;
40 void pop () ;
41 T top () ;
42 ~ Stack () ;
43 };
44 Stack < int > s1 ;
45 s1 . push (1) ;
46 Stack < string > s2 ;
47 s2 . push ( " hello " ) ;
48
49 // Template list class
50 template < typename T >
51 class List {
52 struct Node {
53 T data ;
54 Node * next ;
55 };
56 Node * thelist = nullptr ;
57 public :
58 class Iterators {
59 Node * curr ;
60 explicit Iterator (...) ;
61 public :
62 T & operator *() ...
63 bool operator =(...)
64 Iterator operator ++() ...
65 friend class List <T >;
66 };
67 T & ith ( int i ) ;
68 void addToFront ( T & t ) ;

30
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

69 ~ List () ...
70 };
71 List < int > l1 ;
72 l1 . addToFront (1) ;
73 List < List < int > > l2 ;
74 l2 . addToFront ( l1 ) ;

> Standard Template Library (STL) (std::vector - #include <vector>)

– template class
– dynamic length arrays
∗ heap allocated
∗ automatically resize as needed

1 vector < int > v {3 , 4};


2 v . emplace_back (5) ;
3 v . pop_back () ;
4 for ( int i = 0; i < v . size () ; ++ i ) {
5 cout << v [ i ] << endl ;
6 }
7 for ( vector < int >:: iterator it : v . begin () ; it != v . end () ; ++ it ) {
8 cout << * it << endl ;
9 }
10 for ( auto n : v ) {
11 cout << n << endl ;
12 }
13 for ( vector < int >:: reverse_iterator it = v . rbegin () ; it != v . rend () ; ++ it ) {
14 cout << * it << endl ;
15 }
16 v . erase ( v . begin () ) ;
17 v . erase ( v . end () - 1) ;
18
19 v [ i ] // unchecked access
20 v . at ( i ) // checked access
21 // if i is not in range , out_of_range exception is thrown
22 // After an exception is caught , program continues after the catch slack

> Stack unwinding => when an exception occurs, the call stack is repeatedly popped until an appropriate catch
slack is found

Exception

> Exception recoveries can be done in stages


1 try {...}
2 catch ( Some Exc e ) {
3 // do part recovery
4 throw otherExcep {...}
5 }

i. throw some other exception

31
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

ii. throw e; => throw the caught exception but might have sliced the original exception
iii. throw; throws original exception

> All C++ library exceptions inherit from std::exception

> C++ does not require exceptions to inherit from std::exception

> In C++ you can throw anything

> Good Pratice

i. throw objects of existing exceptions or create your own exception classes


ii. catch by reference outo fr ange∣bada lloc∣lengthe rror

Observer Pattern

> Publish/subscribe model

> Publish - Subject generates data

> Subscribe - Observe wants to be notified of new data

Design Pattern

> Design Philosophy

i. Use abstract base classes to provide interface


ii. USe ptrs to base class that call these interface methods
iii. behaviors changes based on the runtime type of objects

Iterator Pattern

> operator*, operator++, operator !=


1 class AbsIter {
2 public :
3 virtual int & operator *() const = 0;
4 virtual AbsIter & operator ++() = 0;
5 virtual bool operator !=( const AbsIter &) const = 0;
6 virtual ~ AbsIter () {}
7 };
8
9 class List {
10 public :
11 class Iterator : public AbsIter {
12 // List :: Iterator IS A AbsIter
13 };
14 };
15
16 class Set {
17 public :
18 class Iterator : public AbsIter {

32
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

19
20 }; // Set :: Iterator IS A AbsIter
21 }

> We can now implement code that operates using AbsIter and not being tied to a specific data structure
1 template < typename Fn >
2 void foreach ( AbsIter & start , AbsIter & end , Fn f ) {
3 while ( start != end ) {
4 f (* start ) ;
5 ++ start ;
6 }
7 }
8
9 List e ...
10 List :: Iterator i = e . begin () ;
11 foreach (i , e . end () , addTen ( i ) ) ;

Factory Pattern

> The factory method pattern is called the virtual constructor pattern
1 class Level {
2 public :
3 virtual Enemy * createEnemy () = 0;
4 };
5 class Normal : public Level {
6 public :
7 Enemy * createEnemy () override { // more turtles }
8 };
9 class Castle : public Level {
10 Enemy * createEnemy () override { // more bullets }
11 };
12
13 Player * p = ...
14 Level * l = ...
15 Enemy * e = ...
16 while (p - > notDead () ) {
17 // generate enemy should depend on level
18 e =l - > createEnemy () ; // factory of enemy
19 }

Template Method Pattern

> Base class implements the template/skeleton and the subclass fills the blanks

> Base class allows overriding some virtual method but other non-virtual methods must remain unchanged

> Some methods in base class are virtual and some are non-virtual
1 class Turtle {
2 public :
3 void draw () {

33
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

4 drawHead () ;
5 drawShell () ;
6 drawFeet () ;
7 }
8 private :
9 void drawFeet () {}
10 void drawHead () {}
11 virtual void drawShell () = 0;
12 };
13
14 class RedTurtle : public Turtle {
15 void drawShell () override {}
16 }

> Non-virtual Interface(NVI) idiom

Public Virtual Method

> Public(interface) - provide a contract

> Virtual - invitation to subclasses to change behaviour

> Contradictory!

> In a NUI

i. All public methods are non-virtual (expect dtor)


ii. All virtual methods are private/protected

1 class Media {
2 public :
3 void play () {
4 copyrightCheck () ;
5 doPlay () ;
6 }
7 private :
8 virtual void doPlay () = 0;
9 }

Visitor Design Pattern

> In C++, dynamic dispatch does not account for runtime type of parameters
1 class Enemy {
2 public :
3 virtual void strike ( Weapon &) = 0;
4 };
5 class Turtle : public Enemy {
6 public :
7 void strike ( Weapon & w ) override { w . useOn (* this ) ;} // Compile time this ↩
becomes Turtle
8 };
9 class Bullet : public Enemy {

34
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

10 public :
11 void strike ( Weapon & w ) override { w . useOn (* this ) ;} // Compile time this ↩
becomes Bullet
12 };
13 class Weapon {
14 virtual void useOn ( Turtle &) = 0;
15 virtual void useOn ( Bullet &) = 0;
16 };

> Double Dispatch => using a combination of overriding and overloading

Book Hierarchy

> want to add functionality that denepnds on runtiem type of objects


> What is we do not have the source code?

> What if the behaviour does not really nelong to the classes?

> We can do this if the Book hierarchy will accept BookVisitors


1 class Book {
2 public :
3 virtual void accept ( BookVisitors & v ) {
4 v . visit (* this ) ; // * this must be a Book
5 }
6 };
7 class Text : public Book {
8 public :
9 void accept ( BookVisitors & v ) override {
10 v . visit (* this ) ; // * this must be a Text
11 }
12 };
13 class Comic : public Book {
14 public :
15 void accept ( BookVisitors & v ) override {
16 v . visit (* this ) ; // * this must be a Comic
17 }
18 };
19 class BookVisitors {
20 public :
21 virtual void visit ( Book &) = 0;
22 virtual void visit ( Text &) = 0;
23 virtual void visit ( Comic &) = 0;
24 ~ BookVisitors () ;
25 };

STL std::map

> Template class, generalized arrays

> parameterized on 2 types key/value

> key type must support operator<

35
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

1 std :: map < string , int > m ;


2 m [ " abc " ] = 5;
3 m . erase ( " abc ) ;
4 m . count ( " abc " ) ;
5 for ( auto p : m ) { // p = > std :: pair < string , int >
6 cout << p . first << p . second ;
7 } // iteration is sorted key orders

> Cataloging Book

i. author -> # of Book


ii. topic -> # of Text
iii. hero -> # of Comic
iv. string -> int

1 class Catalog : public BookVisitors {


2 map < string , int > cat ;
3 public :
4 void visirt ( Book & b ) override {++ cat [ b . getAuthor () ;]}
5 void visirt ( Comic & c ) override {++ cat [ c . getHero () ;]}
6 }

Compilation Dependencies

> Fix cycle of includes by forward decreasing classes whenever possible

> an include creates a dependency

> best to reduce dependencies

i. avoid cycles
ii. fewer recompilation
iii. faster compile time

> Usage

– include a file at Inheritance


1 # include " a . h "
2 class B : public A {};

– include a file when constructing another class since need to know its size
1 # include " a . h "
2 class C {
3 A a;
4 };

– Forward declaration with pointer but include a file in .cc file

36
©
Fall 2019 CS-246 Object-Oriented Programming Yiming Dai

1 // . h
2 class A ;
3 class D {
4 A * pA ;
5 };
6
7 // . cc
8 # include " a . h "
9 pa - > method () ;

– Forward declaration with constructing methods but include a file in .cc file
1 // . h
2 class A ;
3 class E {
4 A foo ( A a ) ;
5 };
6
7 // . cc
8 # include " a . h "
9 A E :: foo ( A a ) {}

Reduce Dependencies

1 // File " window . h :"


2 # include < xlib / xlib .h >
3 class XWindow {
4 Display * d ;
5 Window w ;
6 GC gc ;
7 public :
8 draw () ;
9 }

37

You might also like