l05 designing classes
TRANSCRIPT
Computer Programming 2Paul Calder
Designing ClassesClass: A blueprint for creating objects
Flinders University / Computer Programming 2 2
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 3
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 4
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 5
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-specific 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: fit for purpose (related to size of scope)
•Correct part of speech•Nouns: variables, params, value-return functions (length(), valueAt(...))•Verbs: void methods (expand(), rotateRight())
•Special case conventions•Predicates: "tobe" phrase (isOpen, willSucceed, hasErrors)•Accessors: get/set convention (getName, setAge)• Idioms: i, j, k for (integer) loops; n, m, p, q for "maths" variables
6
Beware of l, o
•CamelCase for multiword•Classes start with upper•Others start with lower
small scope: short namelarge scope: longer name
Flinders University / Computer Programming 2
#ifndef THING_H#define THING_H
class Thing {public: Thing(); Thing(int initialValue);
void doSomething(int withThisData); int tellMeSomething();
void setAnotherValue(double); double getAnotherValue();
private: int aValue_; double andAnother_;};
#endif
Class Interface
7
If not (yet) defined...
... then define it so it won't be redefined if included again
Constructors
Operational methods
Accessor methods
Instance variables
Flinders University / Computer Programming 2
#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_; }
Class Implementation
8
Include the class header
Scope specifier
Flinders University / Computer Programming 2 9
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
class ... {
..
private: Type attribute_;
public: Type getAttribute() const { return attribute_; }
void setAttribute(Type value) { // safety checks here attribute_ = value; }
...
};
10
Accessor Proformaconst method can be called on an unchangeable object
Flinders University / Computer Programming 2
class Person {
private: int age_;
public: int getAge() const { return age_; }
void setAge(int age) { if (age >= 0 && age_ <= 120) { age_ = age; } }
};
11
Accessor Example
Sanity checking to ensure attribute values are sensible.
Flinders University / Computer Programming 2
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);}
Improve this class
12
class Rect
angle {
public:
Rectangl
e();
int getH
eight() co
nst;
int getW
idth() con
st;
int getX
() const;
int getY
() const;
void set
Position(i
nt x, int
y);
void set
Size(int w
, int h);
};
This code breaks manyrules of style!
Flinders University / Computer Programming 2
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_;}
Much better!
13
✓Temporary variables local
✓Names reveal functions
✓Instance variable names
✓Accessor methods
✓Private instance variables
Computer Programming 2Paul Calder
A Design ExampleA class for counting in circles
Flinders University / Computer Programming 2
int main() {
// What’s 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;
}
15
Counting in Circles
Flinders University / Computer Programming 2 16
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
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_);}
17
Basic Counter
Flinders University / Computer Programming 2
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&); ...}
18
Add OperatorsCopy constructor
Assignment operators
Conversion operator
Counter
c1(2, 0, 9
9);
Counter
c2(c1);
Counter
c3;
c2 = 10;
c3 = c1;
c1 -= 3;
c2 = c1
+ 4;
c3 = c1
+ c2;
cout <<
"Counter:
";
cin >> c
1;
cout <<
c1 << endl
;friend: an ordinary function with privileged access
Flinders University / Computer Programming 2
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_; return *this;}
Counter& Counter::operator =(int other) { setCount(other); return *this;}
Counter::operator int() const { return getCount();}
19
Constructors & assignment
assignment operators return values!
Flinders University / Computer Programming 2
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;}
20
Arithmetic operators
Flinders University / Computer Programming 2
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 == ')') { c = Counter(max, min); c.setCount(count); } else { in.setstate(in.failbit); } } return in;}
std::ostream& operator <<(std::ostream& out, const Counter& c) { out << "(" << c.count_ << "," << c.min_ << "," << c.max_ << ")"; return out;}
21
IO operators
( 3, -10,
10 )
A counter for the range -10 .. +10, with
current value 3.
a friend function: no scope operator
Flinders University / Computer Programming 2
int main() { Counter c1, c2, c3;
cin >> c1; cin >> c2;
c1 = 15; c3 = c1 + c2; c2 += c1.getCount();
cout << c1 << c2 << c3 << endl; }
22
Try it out
Computer Programming 2Paul Calder
Design ExerciseTimes Square text
Flinders University / Computer Programming 2
int main() { TimesSquare message("Hello, world!"); for (int i = 1; i <= message.length(); i++) { cout << message.getText() << endl; message.rotateLeft(); }}
TimesSquare
24
Write a program that implements "TimesSquare" text.
Hello, world!ello, world!Hllo, world!Helo, world!Helo, world!Hell, world!Hello world!Hello,world!Hello,
orld!Hello, wrld!Hello, wold!Hello, word!Hello, worl!Hello, world
Flinders University / Computer Programming 2
#include <string>
class TimesSquare {public: TimesSquare(std::string text);
void rotateLeft(); int length() const; std::string getText() const;
private: std::string text_;};
Basic class definition
25
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
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);}
Basic class implementation
26
Download
TimesS
quare_
0.zip
Flinders University / Computer Programming 2
class TimesSquare {public:TimesSquare(const TimesSquare& other);
TimesSquare(string text = "");
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_;};
Completing the class
27
copy constructor
assignment operator
default parameters
full set of methods
Flinders University / Computer Programming 2
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); } }}
Rotate methods
28
Flinders University / Computer Programming 2
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&);
...};
Operators
29
Is this a
good use of
operator
overloading??
Flinders University / Computer Programming 2
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_);}
Implementing operators
30
Flinders University / Computer Programming 2
int main() { TimesSquare message("");
cout << "Message: "; cin >> message; 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);}
Using the operators
31
What does this mean?
What if the () were missing?
Computer Programming 2Paul Calder
SafeArrayNow that you've done the homework...
Flinders University / Computer Programming 2
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];};
Template class
33
The C++ template mechanism allows a class definition to be parameterised by a type. Define a template version of the class with the type of the array elements as a parameter.
SafeArra
y<int> ai(
10);
SafeArra
y<string>
as(20);
ai[3] =
42;
as[15] =
"Hello";
Flinders University / Computer Programming 2
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];};
Template class
34
The C++ template mechanism allows a class definition to be parameterised by a type. Define a template version of the class with the type of the array elements as a parameter.
SafeArra
y<int> ai(
10);
SafeArra
y<string>
as(20);
ai[3] =
42;
as[15] =
"Hello";
Flinders University / Computer Programming 2
// simple out-of-bounds processingT& SafeArray::operator [](int index) { if (index < 0) return elements_[0]; if (index >= length_) return elements_[length_ - 1]; return elements_[index];}
Out-of-bounds Indexing
35
Consider alternate strategies for dealing with array indexes that fall outside the valid range. What are the merits and
shortcomings of each approach?
SafeArra
y<int> a(2
);
a[0] = 0
;
a[1] = 1
;
a[2] = 2
; // oops
!
cout <<
a[0] << a[
1] << endl
;
Flinders University / Computer Programming 2
// wrap-around out-of-bounds processingT& SafeArray::operator [](int index) { return elements_[index_ % length_];}
// throw exception for out-of-bound indexT& SafeArray::operator [](int index) { if (index < 0 || index >= length_) { string message = "SafeArray index out of range"; throw out_of_range(message); } return elements_[index];
}
Out-of-bounds Indexing
36
Consider alternate strategies for dealing with array indexes that fall outside the valid range. What are the merits and
shortcomings of each approach?
SafeArra
y<int> a(2
);
a[0] = 0
;
a[1] = 1
;
a[2] = 2
; // oops
!
cout <<
a[0] << a[
1] << endl
;
Flinders University / Computer Programming 2
class SafeArray {public: SafeArray(int length); ...private: int length_; int elements_[100];};
Variable-sized array
37
The current class stores the elements in a fixed-size array. What are the consequences of this implementation decision?
How could you overcome those limitations?
SafeArra
y<int> x(1
0); /
/ OK
SafeArra
y<string>
y(100); /
/ just OK
SafeArra
y<float> z
(1000); /
/ OOPS!
Flinders University / Computer Programming 2
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_;}
Variable-sized array
38
The current class stores the elements in a fixed-size array. What are the consequences of this implementation decision?
How could you overcome those limitations?
static array
5length_
elements_ 0 1 2 98 99...3 4 5 6 7
dynamic array
5length_
elements_0 1 2 3 4