Goal Driven Approach to Testing

Download Report

Transcript Goal Driven Approach to Testing

C++
&
Object-Oriented Programming
The Class
A class is a unit of encapsulation
Public operations, and
 private implementation.

2
A class is an abstraction
String abstracts the char * of C,
 stack -- the canonical abstraction
 List
 Student,
 etc.

3
Classes and C structures
default access for class: private
 default access for struct:public

4
Classes

Example of a bad class declaration
class Student {
public:
float gpa;
char * name;
};
5
Classes and structures

Correct example of Class Declaration
class Student {
private:
float gpa;
char * name;
};
 do
we need the “private” designation?
6
Classes: writing set and get functions
class Student {
public:
void setGpa(float g) { gpa = g; }
void setName(char * n) {
name = new char[strlen(n)+1];
strcpy(name, n);
}
private:
float gpa;
char * name;
};
7
Classes and Objects

Declaration of a class variable (i.e. object)
Student s, t;
Student * v;
int i;
float x;
 The
syntax is identical to conventional
variable declarations.
8
Classes

Since class declarations will likely be
used by many program modules, put
them in a header file that can be included
as required
#include “Student.h”
9
Classes and Objects

Access to class data members
s.setGpa(3.5);
s.setName(“Dana”);
v = new Student(4.0, “Fox”);
t = s;

The Student class also needs
constructors
10
Classes: constructors
class Student {
public:
Student();
//default
Student(char*, float);
//conversion
Student(const Student&);
//copy
friend ostream & operator<<(ostream &,
const Student &);
private:
char * name;
float gpa;
};
11
Constructor parameters:
Default: no parameters
 Conversion: parameters to make one
 Copy: the parameter is the copy instance

12
Constructors/destructors
Guarantee that data is initialized
 allow classes to manage memory

 constructors
allocate: new
 destructors deallocate: delete
13
Prefer initialization to assignment
class Student {
public:
Student(int a) : age(a), iq(age+100) {}
Student(int a) { age = a; iq = age + 100; }
private:
int age;
int iq;
};
14
Prefer init to assign

Initialization is more efficient for data
members that are objects:
 init:
uses copy constructor
 assign: uses default constructor and
assignment

only way to pass a parameter to base class
15
Passing param to base class
class Person {
public:
Person(int a) : age(a) {}
private:
int age;
};
class Student : public Person {
public:
Student(int age, float g) : Person(age), gpa(g) {}
private:
float gpa;
};
16
List members in init list in order
that they are declared
class members are initialized in the order of
their declaration in the class! What’s the value of iq?
class Student {
public:
Student(int a) : age(a), iq(age+100) {}
private:
int iq;
int age;
};
17
Exercise to learn constructors

Write 3 constructors and a destructor for
Student class. Test it with:
void fun(Student stu) {}
int main() {
Student a, b(“Darth Maul”, 3.5), c = b;
Student * d = new Student(“Anakin”, 4.0);
cout << *d << endl;
fun(a);
return 0;
}
18
Why is this a bad class definition?
at least 2 member functions missing
class Student {
public:
Student();
//default
Student(char*, float);
//conversion
Student(const Student&);
//copy
friend ostream & operator<<(ostream &,
const Student &);
private:
char * name;
float gpa;
};
19
Q: what output should we get:
int main() {
Student x(“Count Dooku”), y(“Anakin”);
x = y;
y.setName(“Darth Maul”);
cout << x << endl;
}
Soln: need deep copy: operator=
20
Copying a class object
Original
Object
Shallow
Copy
21
Copying a class object
Original
Object
Deep
Copy
22
Canonical orthodox class form
J. Coplien
Default constructor
 copy constructor
 destructor
 assignment operator

23
What functions does C++
silently write?
class Empty{};
class Empty {
public:
Empty();
Empty(const Empty &);
~Empty();
Empty& operator=(const Empty &);
Empty * operator&();
const Empty * operator&() const;
};
24
How would you need them?
const Empty e1;
// need default constructor, and
// destructor
Empty e2(e1);
e2 = e1;
// copy constructor
// assignment operator
Empty * pe2 = &e2;
// address-of operator (non const)
const Empty *pe1 = &e1; // address-of operator (const)
25
What do the compiler generated
functions look like?
inline Empty::Empty() {}
inline Empty::~Empty() {}
inline Empty * Empty::operator&() { return this; }
inline const Empty * Empty::operator&() const {
return this;
}
The copy constructor and assignment operator simply
do a member wise copy, i.e., shallow. Note that the
default assignment induces a memory leak in Student!
26
When do we need to write a copy constructor,
destructor & assign operator?



Anytime the class has heap-based data members
all base classes should have a virtual destructor
Studies have shown that, if you don’t need
copy/assign, the compiler generated functions
run 10-20% faster than programmer generated
ones.
27
How do we overload assignment?
Student & operator=(const Student & stu) {
if (*this == stu) return * this;
delete [] name;
name = new char[strlen(stu.name)+1];
strcpy(name, stu.name);
gpa = stu.gpa;
return *this;
}
(1) Why the comparison on the first line?
(2) Could the first line be: if (this == &stu)?
(3) Why return *this? What does it enable?
(4) Why not return stu, rather than *this?
28
Formula for overloaded assignment
Check for equality of lhs & rhs
 delete storage for lhs
 create new storage for lhs, that’s size of
rhs
 copy rhs “stuff” to lhs
 return *this

29
an overloaded binary operator

can be written in infix form
a = b;
 cout << stu;


or can be written in prefix form
 a.operator=(b)
 cout.operator<<(stu)
30
Principle of least privilege




Can reduce debugging and provide
documentation by only allowing a function the
least amount of privilege
can prevent a function from modifying a
parameter
can prevent a member function from
modifying data attributes
allow a function enough data access to
accomplish its task – and no more!
31
Explicitly disallow any implicit
functions you don’t want!
Suppose you want to write a class
template array that behaves like C++
arrays, except that it does bounds check
 C++ does not allow array assignment; e.g.
int a[10], b[10]; a = b; //error

class Array {
private:
Array & operator=(const Array & );
};
don’t define the
operator= to keep
member & friend
functions from
using it!
32
Overloading operators
almost all operators can be overloaded
 operators are binary or unary
 have the same precedence as their
compiler counterpart
 can be members or friends, usually
 overloaded output operator cannot be a
member of any user defined class

33
overloading output operator:
as a friend function
class Student {
public:
getName() { return name; }
getGpa() { return gpa; }
friend ostream & operator<<(ostream &, const Student &);
private:
char * name;
float gpa;
};
ostream & operator<<(ostream & out, const Student & s) {
out << s.getName() << “\t” << s.getGpa();
return out;
34
}
Overloading output operator:
as stand-alone function
class Student {
public:
getName() { return name; }
getGpa() { return gpa; }
private:
char * name;
float gpa;
};
ostream & operator<<(ostream & out, const Student & s) {
out << s.getName() << “\t” << s.getGpa();
return out;
}
35
Put prototype in header file,
and body in implementation file
class Student {
public:
getName() const { return name; }
getGpa() const { return gpa; }
private:
char * name;
float gpa;
};
ostream & operator<<(ostream &, const Student &);
ostream & operator<<(ostream & out, const Student & s) {
out << s.getName() << “\t” << s.getGpa();
return out;
}
36
Exercise with classes:
Complete the definition of Student with
all 3 constructors, overloaded
assignment, overloaded output, and get
and set
 Write a main program that contains 2
functions:

a
function to init the list with 3 Students
 a function that prints the list
37
Using students
In actual practice, we want to store lots
of students
 need an array of students
Student list[10];
Q: How many times does a constructor
get called for list?
Q: which constructor?

38
What’s missing:

Need an easier way to print a student
 overload
the output operator <<
 operator<< must be a friend function;
cannot be a member function cuz it’s
already a member of class ostream

Need a class to manage the list of
Students
39
Friends
Can access private member functions
and private data attributes!
 Can be functions or classes
 Might not always be best solution!

40
Overloading the output operator
Class Student {
public:
friend ostream & operator<<(ostream & out,
const Student & student){
out << student.name;
return out;
}
};
41
Class StudentManager {
public:
StudentManager() : count(0) { }
void insert(const Student &);
friend ostream & operator<<(ostream &, const Student &);
private:
int count;
Student list[100];
};
42
42
Class StudentManager {
public:
StudentManager() : count(0) {}
void insert(const Student & student) {
list[count++] = student;
}
friend ostream & operator<<(ostream & out,
const Student & student) {
for (int i = 0; i < count; ++i) out << student[i] ;<< endl;
return out;
}
private:
int count;
Student list[100];
};
43
43
Class exercise:
Complete the StudentManager Class;
 rewrite main to use the List Class.
 Write a new main program that allows
the user to choose among commands:

 insert
student
 delete student
 print the list
 find a student
 exit
44
Discussion of Manager class:

Advantages:
 encapsulates
functionality into a single
class
 simplifies the main program

Disadvantages:
 there
is a limit (100) on number of Students
 Student’ default constructor called 100
times!
45
Suggested Naming Conventions





global constants: ALL CAPS!
local & global variables: ALL LOWER CASE,
USE UNDERSCORE
Class names: BEGIN EACH WORD WITH
UPPER CASE, NO UNDERSCORE
Class member functions: BEGIN LOWER
CASE, then BEGIN EACH WORKD WITH
UPPER CASE
Data members: SAME AS MEMBER
FUNCTIONS
46
Operator Overloading:
ADT for binary math

Would like variables of type binary to be
like any other data type. Thus:
 overload
arithmetic operators
 overload output to be binary
 overload input to use decimal

How do we represent internally?
47
Binary should “look like” int
#include “Binary.h”
main() {
int sum = 0;
Binary number1, number2 = 7;
number1 = 15;
cout << number1 + number2 << endl;
}
48
// This is file Binary.h
class Binary {
public:
Binary() : number(0) {}
Binary(int n) : number(n) {}
Binary(const Binary & bin);
Binary operator+(const Binary &);
Binary& operator++();
Binary& operator=(const Binary &);
friend ostream & operator<<(ostream &, const Binary &);
private:
int number;
};
49
49
#include “Binary.h” // this is file Binary.cpp
Binary Binary::operator+(const Binary & rhs) {
Binary temp(number+rhs.number);
return temp;
}
Binary& operator++() {
++number;
return *this;
}
50
50
// this is a global function; s/b in Binary.cpp
ostream & operator<<(ostream & out, const Binary & bin) {
stack<int> stk;
int number = bin.number;
while (number) {
stk.push( number % 2 );
number /= 2;
}
while ( !stk.empty() ) {
out << stk.top();
stk.pop();
}
return out;
}
51
51
Exercise for Binary type:



Complete the class definition for Binary
construct a main program that uses Binary
Discuss return value transmission mode




operator=
operator++
operator+ (postfix, prefix)
Discuss merits of friend vs member functions
for +, ++, output, etc.
52
Discussion of Binary class
Compilation can be made simpler by
using a makefile
 makefile automatically compiles and
links program modules
 makefiles are mysterious

53
makefile/Makefile
Consist of definitions,
 Followed by sequences of 2 line
commands.

 Begins
with id:, followed by dependencies
of id.
 Second line is the rule to make id; this line
MUST be preceded by a tab

To use the make file type: make {<id>}
54
CCC=g++
FLAGS=-Wall
main: main.o Binary.o
$(CCC) $(FLAGS) -o main main.o Binary.o
main.o: main.cpp Binary.h
$(CCC) $(FLAGS) -c main.cpp
Binary.o: Binary.cpp Binary.h
$(CCC) $(FLAGS) -c Binary.cpp
clean:
rm -f main *.o core
55
55
Discussion of makefile
$(CCC) permits us to easily switch to
another compiler; e.g. CC
 make clean will ‘clean’ the directory of
large files
 -o option creates an executable
 -c option creates .o file

56
C-strings are no fun:
Programmer must manage memory
 comparison is awkward
 concatenation is non-standard

 strcat(a,
a

b), instead of:
+b
No substring facilities
57
Solution: write our own String class
What do we need:

Constructors
 default
 conversion
 copy

overloaded operators
 output
 concatenation
58
Dynamic storage
Need pointers
 “never” run out of room ;-)
 must allocate storage: new
 must also deallocate storage: delete
 failure to deallocate storage: memory
leak
 constructors/destructors were designed
to facilitate memory management

59
// This class definition of String s/b in file: String.h
class String {
public:
String();
String(char *);
String(const String &);
String operator+(const String &);
int len() const ;
friend ostream & operator<<(ostream &, const String &);
private:
char * buf;
};
60
60
// This class definition of String s/b in file: String.h
class String {
public:
String(int n = 0) : buf(new char[n+1]) { buf[0] = ‘\0’; }
String(char * s) : buf(new char[strlen(s)+1]) { strcpy(buf, s); }
String(const String &);
~String() { delete [] buf; }
char & operator[](int i) { return buf[i]; }
String operator+(const String &);
int len() const { return strlen(buf); }
friend ostream & operator<<(ostream &, const String &);
private:
char * buf;
};
61
61
// This is file String.cpp
#include “String.h”
ostream & operator<<(ostream & out, const String & s) {
out << s.buf;
return out;
}
String String::operator+(const String & rhs) {
String temp( strlen(buf)+strlen(rhs.buf) );
strcpy(temp.buf, buf);
strcat(temp.buf, rhs.buf);
return temp;
}
62
62
We need operator==

Discuss the merits of the following
comparison function:
bool String::operator==(const String & rhs) {
return (*this == rhs);
}
63
String exercise:
Discuss ‘what’s missing’ from String
spec
 Complete the class definition and
implementation; write copy constructor
 Write a main program that uses Strings.
 Write a makefile
 Thoroughly test the class
 Is there one in the standard C++ library?

64
String exercise:
Add operator= to String
 Q: when are constructors called?
 Q: when is assignment called?
 Q: which is better: initialization or
assignment?
 Consider main.cpp, String.h and
String.cpp

65
#include “String.h”
String & String::operator=(const String & rhs) {
if (*this == rhs) return *this;
delete [] buf;
buf = new char[strlen(rhs.buf) + 1];
strcpy(buf, rhs.buf);
return *this;
}
66
66
Discussion of String::operator=





Note the return transmission mode. Why?
what happens if we do not delete buf?
Why do we need +1 when we new buf ?
What does return *this mean?
Discuss the following 3 options:



if (*this == rhs) return *this;
if (this == &rhs) return *this;
if (strcmp(buf, rhs.buf) ==0) return *this;
67
#include “String.h”
int main() {
String a, b(“hello”),
c(a), d = “world”;
}
What constructors are called?
68
68
// Note that it’s more efficient if constructors
// use initialization rather than assignment.
// To see: place cout in constructors for String!
class Test {
public:
Test(char *n) : name(n) {} // initialization
Test(char *n) { name = n; } // assignment
private:
String name;
};
main() {
Test t(“surprise”);
}
69
69
Making Strings useful:
Sometimes we want to ‘run through’ a
string; i.e. iterate through the string.
 For example, if we read a line of text
from a file, we might want to access
each word on the line.
 Can write a special class called an
iterator

70
Iterator class
Allows user to ‘look at’ each item in the
data structure
 can be forward or backward
 can have more than one iterator on a
given data structure

71
iterator
For a linked list: would return each item
in the list, starting with the first an
proceeding through the list;
 for a string: might return each word in
the list, or it might return each character
 for a tree: would return each item in the
tree, in some order (preorder, depth first,
etc.)

72
// partial specification for iterator over String
class StringIterator {
public:
StringIterator(const String & s, char d = ‘ ‘)
: str(s), index(0) , delim(d) {}
void operator++();
String operator() () const;
bool atEnd() const { return index == str.len(); }
private:
String str;
unsigned int index;
char delim;
};
73
73
StringIterator spec discussion
Constructor must init data members in
the order that they are listed in the
declaration
 default delimiter is a blank
 overloaded parens looks odd
 note that str.len() is one past the end!
 we could overload operator<< for
debugging

74
// implementation of operator++
#include “StringIterator.h”
void StringIterator::operator++() {
while (index < str.len() && str[index] != delim) ++index;
while (index < str.len() && str[index] == delim) ++index;
}
75
75
// implementation of operator()
String StringIterator::operator() () const {
char buf[80];
int temp_index = index, i = 0;
while (temp_index < str.len() && str[temp_index] != delim)
buf[i++] = str[temp_index++];
buf[i] = ‘\0’;
return String(buf);
}
76
76
StringIterator exercises:
Complete the specification and
implementation
 overload operator<< for debugging
 thoroughly test your ADT
 extend StringIterator to accept a set of
delimiters
 what happens if you initialize the data
members in different order than they are
77
declared?

Stack: a common data structure

Public operations:
 push
 pop
 test
empty
 possibly test full

private data representation
The canonical abstraction
78
class IntStack {
public:
IntStack() : count(EMPTY) {}
void push(int n)
{ items[++count] = n; }
void pop()
{ --count; }
int top() const
{ return items[count]; }
bool isEmpty() const { return count == EMPTY; }
bool isFull() const { return count == 99; }
private:
enum {EMPTY = -1};
int items[100];
int count;
};
79
79
Stack exercise:
Implement and test Stack class
 Discuss alternatives to items[100]
 modify IntStack so that it accepts a
parameter describing the size of items
 Discuss drawbacks of IntStack
 What are solutions to drawbacks?

80
Template classes
Functions accept variables as
parameters
 template classes accept types as
parameters
 functions can also use templates

81
template <class T>
class Stack {
public:
Stack() : count(EMPTY) {}
void push(const T & n) { items[++count] = n; }
void pop()
{ --count; }
const T top() const { return items[count]; }
bool isEmpty() const { return count == EMPTY; }
bool isFull() const { return count == 99; }
private:
enum {EMPTY = -1};
T items[100];
int count;
};
82
82
Discussion of template stack
Note the change in parameter
transmission from IntStack to Stack<T>
 Note that top() passes return by value;
can pass-by-value return be avoided?
 Can arrays, in C++, be dimensioned
dynamically?
 What happens if user pops from empty
stack?

83
Exceptions
Useful for handling error conditions.
 Also useful for exceptional cases, such
as eof, end-of-line, etc.
 keywords: try, catch, throw

84
How to use exceptions
Each try block has corresponding catch
block(s)
 calls to functions that may throw an
exception are placed in a try block.
 The called function, when faced with
exceptional condition, performs a throw
 the exception is thrown back, through
the call chain, to matching catch, or
 program bombs!

85
// give the output for the program below:
void fun(int number) {
if (number % 2 == 0) throw “error”;
cout << “This is fun” << endl;
}
main() {
try {
fun(2);
fun(3);
}
catch (char * msg) {
cout << msg << endl;
return 1;
}
}
86
// give the output for the program below:
void fun(int number) {
if (number % 2 == 0) throw “error”;
cout << “This is fun” << endl;
}
main() {
int n = 2;
while (n) {
try { fun(n--); }
catch (char * msg) {
cout << msg << endl;
}
}
}
87
class Clean {
public:
Clean() { cout << “constructing Clean” << endl; }
~Clean() { cout << “destroying Clean” << endl; }
};
void fun() {
Clean c;
throw “error”;
}
main() {
try { fun(); }
catch(char * msg) { cout << msg << endl; }
}
88
Stack exercise
Add exception handling to Stack class
 write a main program with try/catch
block that uses Stack

89
Dynamic storage
Need pointers
 “never” run out of room ;-)
 must allocate storage: new
 must also deallocate storage: delete
 failure to deallocate storage: memory
leak
 constructors/destructors were designed
to facilitate memory management
90

Linked list
Dynamic memory used to store data
(usually in a node!)
 node usually stores data and pointer to
next node (at least)
 can be singly linked, doubly linked,
circularly linked
 can have dummy header node and/or
dummy footer node

91
Singly linked list
node
node
node
92
// partial specification & implementation for Node class
class Node {
public:
friend class List;
Node() : data(0), next(NULL) {}
Node(int d, Node * n) : data(d), next(n) {}
int getData() const;
void setData(int d) ;
friend ostream & operator<<(ostream &,
const Node &);
private:
int data;
Node * next;
};
93
93
// partial specification & implementation for Node class
class Node {
public:
friend class List;
Node(int d = 0, Node * n = NULL) : data(d), next(n) {}
int getData() const { return data; }
void setData(int d) { data = d; }
friend ostream & operator<<(ostream & out,
const Node & node) {
out << node.data; return out;
}
private:
int data;
Node * next;
94
94
};
#include “Node.h”
class List{
public:
List() : head(NULL), current(NULL) {}
void insert(int data) { head = new Node(data, head); }
void delete() {
Node * temp = head; head = temp->next; delete temp;
}
Node * getFront() { current = head; return current; }
Node * getNext() { current=current->next; return current:}
friend ostream & operator<<(ostream &, const List &);
private:
Node * head;
Node * current;
95
95
};
Discussion of List class






insert actually inserts at the front
getFront, getNext and current allow us to iterate
through the list. Is there a better way?
Why is List a friend of Node?
Can we construct Node and List so that
friendship is not required?
Note that deleting an arbitrary element is tricky.
Would a doubly linked list simplify?
Should List be templated?
96
List class exercise





Complete specification & implementation,
adding insertAtRear, insertAtFront, insert,
deleteFront, deleteRear, deleteNth, ...
Write a main program that uses List and test
Re-write Node and List so that friendship is
not required.
Push the envelope: template List
Write an iterator class for List
97
List exercise
Find a solution to the Josephus problem
for inputs n and m
 describe a solution, using IntList, to the
problem of arbitrary precision arithmetic.
Compare the speed of your program
with bc on unix.

98
Doubly linked list
Easier to delete an arbitrary element
 more overhead to implement
 more storage
 sometimes use a dummy header node
to facilitate inserting into an empty list
and deleting from a list of size 1.
 Can use a pointer to the front and rear,
facilitating insertion at either end.

99
Doubly linked list
dummy
node
node
prev number next
100
#include <iostream.h>
class Node {
public:
friend class List;
friend class ListIterator;
Node(int i = 0, Node * n = NULL, Node * p = NULL)
: number(i), next(n), prev(p) {}
friend ostream & operator<<(ostream &, const Node &);
private:
int number;
Node * next;
Node * prev;
}
101
#include “Node.h”
class List {
public:
friend class ListIterator;
List() { rear = front = new Node; }
void insertAtFront(int n);
void insertAtRear(int n);
bool empty const { return front == rear; }
int size() const;
friend ostream & operator<<(ostream &, const List &);
private:
Node * front;
Node * rear;
}
102
class ListIterator {
public:
ListIterator (const List & list)
: front(list.front), current(list.front->next) {}
void init()
{ current = front; }
void operator++()
{ current = current->next; }
Node * operator() () const { return current; }
bool more() const { return current != NULL; }
private:
Node * front;
Node * current;
};
103
Doubly linked list exercises
Complete the spec and implementation
 test the list

104