You are on page 1of 13

Computer Programming 2

Paul Calder

Designing Classes
Class: A blueprint for creating objects

Program Design
!Look for the objects
! Think "objects interacting" ! Nouns and noun phrases

!Decide on the classes


! Similar kinds of objects ! Category nouns ! "Is-a" relationships

Flinders University / Computer Programming 2

Class Design
!Actions: what task?
! Verbs and verb-phrases ! Associate actions with key objects ! Who does the "doing"?

!Information: what data?


! Attributes for object state ! Parameters for method information

Flinders University / Computer Programming 2

Class Structure
!Scope
! Of a declaration: variable, method, class ! Where should this be visible? Who needs to use this?

!Visibility
! Locals & parameters - just that method call ! Private - any method of that class ! Public - anyone

Flinders University / Computer Programming 2

Thin Interfaces
!Minimise public
! Easier to understand: "need-to-know" ! Easier to change: "information hiding"

!Minimise attributes
! Locals for temporary values ! Parameters to provide call-specic information ! Attributes only if no other mechanism possible!

!Accessors
! Controlled access to attributes (instance state)

Flinders University / Computer Programming 2

Function-Revealing Names
!Names tell the story
! Real words, not (gratuitous) abbreviations ! Length: t for purpose (related to size of scope)
CamelCase for multiword Classes start with upper Others start with lower
small scope: short name large scope: longer name

!Correct part of speech


! Verbs: void methods (expand(), rotateRight())

! Nouns: variables, params, value-return functions (length(), valueAt(...))

!Special case conventions


! Predicates: "tobe" phrase (isOpen, willSucceed, hasErrors) ! Accessors: get/set convention (getName, setAge)
Beware of l, o

! Idioms: i, j, k for (integer) loops; n, m, p, q for "maths" variables


Flinders University / Computer Programming 2 6

Class Interface
If not (yet) defined... #ifndef THING_H #define THING_H class Thing { public: Thing(); Thing(int initialValue); ... then define it so it won't be redefined if included again Constructors Operational methods Accessor methods

void doSomething(int withThisData); int tellMeSomething(); void setAnotherValue(double); double getAnotherValue(); private: int aValue_; double andAnother_; }; #endif

Instance variables

Flinders University / Computer Programming 2

Class Implementation
#include "Thing.h" Thing::Thing() { ... } Thing::Thing(int initialValue) { ... } void Thing::doSomething(int withThisData) { ... } int Thing::tellMeSomething() { ... return ...; } void Thing::setAnotherValue(double v) { andAnother_ = v; } double Thing::getAnotherValue() { return andAnother_; } Include the class header

Scope specifier

Flinders University / Computer Programming 2

Accessor Methods
!Access to state
! Clients need to know ! But supplies need to maintain control

!Solution
! Make attribute variable private ! Public "get" method if read needed ! Public "set" method if write needed

Flinders University / Computer Programming 2

Accessor Proforma
class ... { .. private: Type attribute_; public: Type getAttribute() const { return attribute_; } void setAttribute(Type value) { // safety checks here attribute_ = value; } ... }; const method can be called on an unchangeable object

Flinders University / Computer Programming 2

10

Accessor Example
class Person { private: int age_; public: int getAge() const { return age_; } void setAge(int age) { if (age >= 0 && age_ <= 120) { age_ = age; } } }; Sanity checking to ensure attribute values are sensible.

Flinders University / Computer Programming 2

11

Improve this class


class Controller { public: Rectangle re; int x; int x1; int x2; int s; int x3; int x4; int s1; Controller(Rectangle r); void mover(int s); void changer(int m); Controller::Controller(Rectangle r) { re = r; } void Controller::mover(int s) { x = re.getX(); x2 = re.getY(); x1 = x + s; re.setPosition(x1, x2); } void Controller::changer(int m) { s = re.getHeight(); x3 = re.getX() + s/2; x4 = re.getY() + s/2; s1 = s - m; re.setSize(s1, s1); re.setPosition(x3 - s1/2, x4 - s1/2); }

};

{ gle ctan s Re clas c: ; nst; ) i publ tangle( ht() co t; Rec etHeig ) cons ( g h t t d n ; i i ); onst getW nt y int etX() c nst; x, i o g int etY() c ion(int nt h); i t g i , s t w o n i setP (int void setSize void };

This c break ode s rules many of sty le!


12

Flinders University / Computer Programming 2

Much better!
class TargetController { public: TargetController(Rectangle); void moveUp(int step); void shrink(int step); void setTarget(Rectangle); Rectangle getTarget() const; private: Rectangle target_; }; TargetController::TargetController(Rectangle target) { target_ = target; } void TargetController::moveUp(int step) { int x = target_.getX(); int y = target_.getY(); x += step; target_.setPosition(x, y); } void TargetController::shrink(int step) { ing size = target_.getHeight(); int midX = target_.getX() + size/2; int midY = target_.getY() + size/2; size -= step; target_.setSize(size, size); target_.setPosition(midX - size/2, midY - size/2); } void TargetController:: setTarget(Rectangle target) { target_ = target; } Rectangle TargetController::getTarget() const { return target_; }

s local variable porary l functions m e T ! mes revea ames !Na tance variable ns d s !In essor metho ariables !Acc ate instance v !Priv

Flinders University / Computer Programming 2

13

Computer Programming 2
Paul Calder

A Design Example
A class for counting in circles

Counting in Circles
int main() { // Whats 6 months after October? Counter month(1, 12); month.setCount(10); month.step(6); cout << month.getCount() << endl; // If I start at 5pm and work for 20 hours straight, what time would I finish? Counter hour(0, 23); hour.setCount(17); hour.step(20); cout << hour.getCount() << endl;

Flinders University / Computer Programming 2

15

Counter Design
!Thin interface
! Constructor: count limits ! Operational: step by n with wrap around ! Accessor: controlled read and write access

!Minimise visibility
! Choose local before private before public ! Minimise public interface

!Function-revealing names
! Methods, variables, parameters

Flinders University / Computer Programming 2

16

Basic Counter
class Counter { public: Counter( int count = 0, int lowest_ = 0, int highest_ = INT_MAX ); void step(int size = 1); int getCount() const; void setCount(int count); private: int count_; int lowest_; int highest_; }; Counter::Counter(int count, int lowest, int highest) { lowest_ = min(lowest, highest); highest_ = max(lowest, highest); setCount(count); } void Counter::step(int size) { // simple but inefficient! while (size > 0) { count_ += 1; if (count_ > highest_) count_ = lowest_; } while (size < 0) { count_ -= 1; if (count_ < lowest_) count_ = highest_; } } int Counter::getCount() const { return count_; } void Counter::setCount(int count) { count = count; count_ = min(count_, highest_); count_ = max(count_, lowest_); }

Flinders University / Computer Programming 2

17

Add Operators
Copy constructor
class Counter { public: ... Counter(const Counter&); Counter& operator =(const Counter&); Counter& operator =(int); operator int() const; Counter& operator +=(int step); Counter& operator -=(int step); Counter operator +(int step); Counter operator -(int step); friend std::istream& operator >>(std::istream&, Counter&); friend std::ostream& operator <<(std::ostream&, const Counter&); ...
99); , 0, c1(2 ); 1 ter Coun er c2(c t Coun er c3; t Coun 10; c2 = c1; c3 = = 3; c1 - c1 + 4; ; c2 = c1 + c2 = "; c3 er: ount < "C < t cou > c1; < endl; > cin << c1 < cout

Assignment operators Conversion operator

friend: an ordinary function with privileged access

Flinders University / Computer Programming 2

18

Constructors & assignment


Counter::Counter(const Counter& other) { count_ = other.count_; lowest_ = other.lowest_; highest_ = other.highest_; } Counter& Counter::operator =(const Counter& other) { count_ = other.count_; lowest_ = other.lowest_; highest_ = other.highest_; assignment return *this; } Counter& Counter::operator =(int other) { setCount(other); return *this; } Counter::operator int() const { return getCount(); }

operators return values!

Flinders University / Computer Programming 2

19

Arithmetic operators
Counter& Counter::operator +=(int step) { step(step); return *this; } Counter& Counter::operator -=(int step) { step(-step); return *this; } Counter Counter::operator +(int step) { Counter result(*this); result += step; return result; } Counter Counter::operator -(int step) { Counter result(*this); result -= step; return result; }

Flinders University / Computer Programming 2

20

IO operators
std::istream& operator >>(std::istream& in, Counter& c) { char d1, d2, d3, d4; int count, min, max; if (in >> d1 >> count >> d2 >> min >> d3 >> max >> d4) { if (d1 == '(' && d2 == ',' && d3 == ',' && d4 == ')') { 10 ) c = Counter(max, min); -10, c.setCount(count); ( 3, } else { r the in.setstate(in.failbit); ter fo } coun alue 3. A v } nt curre return in; } std::ostream& operator <<(std::ostream& out, const Counter& c) { out << "(" << c.count_ << "," << c.min_ << "," << c.max_ << ")"; return out; }

-10 range

, with .. +10

a friend function: no scope operator

Flinders University / Computer Programming 2

21

Try it out
int main() { Counter c1, c2, c3; cin >> c1; cin >> c2; c1 = 15; c3 = c1 + c2; c2 += c1.getCount(); } cout << c1 << c2 << c3 << endl;

Flinders University / Computer Programming 2

22

Computer Programming 2
Paul Calder

Design Exercise
Times Square text

TimesSquare
Write a program that implements "TimesSquare" text.
Hel l ell o, wor o llo , worl ld! , w orl d!H lo, d o, world! !He wor ld! Hel , w H or e wor ld!Hel ll wor ld!Hel lo orl ld!Hel lo, d l rld !Hello o, ! ld! Hello, , w Hel lo, wo d!H e !He llo, w wor llo , w orl orl d

int main() { TimesSquare message("Hello, world!"); for (int i = 1; i <= message.length(); i++) { cout << message.getText() << endl; message.rotateLeft(); }

Flinders University / Computer Programming 2

24

Basic class denition


#include <string> class TimesSquare { public: TimesSquare(std::string text); void rotateLeft(); int length() const; std::string getText() const; private: std::string text_; };

Shouldn't put using namespace statement into header files, because users do not want to be locked in. Therefore need fully specified names.

Flinders University / Computer Programming 2

25

Basic class implementation


TimesSquare::TimesSquare(string s) { text_ = s; } int TimesSquare::length() const { return text_.length(); } string TimesSquare::getText() const { return text_; } void TimesSquare::setText(string s) { text_ = s; } void TimesSquare::rotateLeft() { text_.insert(text_.length, 1, text_[0]); text_.erase(0, 1); }

Tim

ip ad nlo _0.z w Do are u sSq

Flinders University / Computer Programming 2

26

Completing the class


class TimesSquare { public: TimesSquare(const TimesSquare& other); TimesSquare(string text = "");

copy constructor default parameters

TimesSquare& operator =(const TimesSquare& other); void rotateLeft(int steps = 1); void rotateRight(int steps = 1); int length() const; string getText() const; void setText(string s); private: string text_; };

assignment operator full set of methods

Flinders University / Computer Programming 2

27

Rotate methods
void TimesSquare::rotateRight(int steps) { int length = text_.length(); if (length > 0) { for (int i = 0; i < steps; i++) { text_.insert(0, 1, text_[length - 1]); text_.erase(length, 1); // briefly one character longer } } } void TimesSquare::rotateLeft(int steps) { int length = text_.length(); if (length > 0) { for (int i = 0; i < steps; i++) { text_.insert(length, 1, text_[0]); text_.erase(0, 1); } } }

Flinders University / Computer Programming 2

28

Operators
class TimesSquare { public: ... TimesSquare& operator <<=(int shift); TimesSquare& operator >>=(int shift); friend TimesSquare operator <<(TimesSquare t, int shift) { return t <<= shift; } friend TimesSquare operator >>(TimesSquare t, int shift) { return t >>= shift; } friend ostream& operator <<(ostream&, const TimesSquare&); friend istream& operator >>(istream&, TimesSquare&); }; ...

a his Is t use of d goo erator g?? op adin rlo ove

Flinders University / Computer Programming 2

29

Implementing operators
TimesSquare& TimesSquare::operator <<=(int shift) { rotateLeft(shift); return *this; } TimesSquare& TimesSquare::operator >>=(int shift) { rotateRight(shift); return *this; } ostream& operator <<(ostream& out, const TimesSquare& from) { return out << from.text_; } istream& operator >>(istream& in, TimesSquare& to) { return getline(in, to.text_); }

Flinders University / Computer Programming 2

30

Using the operators


int main() { TimesSquare message(""); cout << "Message: "; cin >> message;

What if the () were missing?

for (int i = 1; i <= message.length(); i++) { cout << (message << i) << endl; } for (int i = 1; i <= message.length(); i += 2) { cout << (message >>= 2) << endl; } } cout << (message << 3 >> 5);

What does this mean?

Flinders University / Computer Programming 2

31

Computer Programming 2
Paul Calder

SafeArray
Now that you've done the homework...

Template class
The C++ template mechanism allows a class denition to be parameterised by a type. Dene a template version of the class with the type of the array elements as a parameter.
template <T> class SafeArray { public: SafeArray(int length); SafeArray& operator =(const SafeArray& other); bool operator ==(const SafeArray& other) const; bool operator !=(const SafeArray& other) const; int length() const; T& operator [](int index); private: int length_; T elements_[100]; };

); ; i(10 t> a as(20) n i < > y Arra <string e f a y S Arra Safe 42; lo"; l ] = ai[3 ] = "He 5 as[1

Flinders University / Computer Programming 2

33

Template class
The C++ template mechanism allows a class denition to be parameterised by a type. Dene a template version of the class with the type of the array elements as a parameter.
template <T> class SafeArray { public: SafeArray(int length); SafeArray& operator =(const SafeArray& other); bool operator ==(const SafeArray& other) const; bool operator !=(const SafeArray& other) const; int length() const; T& operator [](int index); private: int length_; T elements_[100]; };

; (10) 0); 2 > ai <int ng> as( y a r ri Ar Safe rray<st A Safe 42; lo"; l ] = ai[3 ] = "He 5 as[1

Flinders University / Computer Programming 2

34

Out-of-bounds Indexing
Consider alternate strategies for dealing with array indexes that fall outside the valid range. What are the merits and shortcomings of each approach?
// simple out-of-bounds processing T& SafeArray::operator [](int index) { if (index < 0) return elements_[0]; if (index >= length_) return elements_[length_ - 1]; return elements_[index]; }

2); > a( <int y a r Ar Safe = 0; ps! a[0] = 1; / oo ndl; a[1] = 2; / << e [1] a a[2] < < [0] << a cout

Flinders University / Computer Programming 2

35

Out-of-bounds Indexing
Consider alternate strategies for dealing with array indexes that fall outside the valid range. What are the merits and shortcomings of each approach?
// wrap-around out-of-bounds processing T& SafeArray::operator [](int index) { return elements_[index_ % length_]; } // throw exception for out-of-bound index T& SafeArray::operator [](int index) { if (index < 0 || index >= length_) { string message = "SafeArray index out of range"; throw out_of_range(message); } return elements_[index]; }

(2); t> a y<in a r r A Safe = 0; ps! a[0] = 1; / oo ndl; a[1] = 2; / << e a[1] a[2] < < [0] << a cout

Flinders University / Computer Programming 2

36

Variable-sized array
The current class stores the elements in a xed-size array. What are the consequences of this implementation decision? How could you overcome those limitations?
class SafeArray { public: SafeArray(int length); ... private: int length_; int elements_[100]; };

K // O st OK ju / ; / ) ! x(10 OOPS 0); int> g> y(10 ); // < y a 000 rin Arr Safe rray<st at> z(1 o A Safe rray<fl A Safe

Flinders University / Computer Programming 2

37

Variable-sized array
The current class stores the elements in a xed-size array. What are the consequences of this implementation decision? How could you overcome those limitations?
class SafeArray { public: SafeArray(int length); ... private: int length_; T* elements_; }; SafeArray::SafeArray(int length) { length_ = length; elements = new T[length_]; } SafeArray::~SafeArray() { delete[] elements_; } static array

length_ elements_
dynamic array

5
0 1 2 3 4 5 6 7

...

98

99

length_ elements_

Flinders University / Computer Programming 2

38

You might also like