Вы находитесь на странице: 1из 7

Introduction

Object-Oriented Design and


 Container classes are an important cate-
Programming gory of ADTs
{ They are used to maintain collections of ele-
ments like stacks, queues, linked lists, tables,
trees, etc.
C++ Container Classes
 Container classes form the basis for vari-
ous C++ class libraries
{ Note, making class libraries is a popular way to
Outline learn C++ :::

Introduction  C++ container classes can be implemented


using several methods:
Container Class Objectives
Class Library Architecture (0) Ad hoc, rewrite from scratch each time
(1) Preprocessor Macros
Parameterized Types (2) A genclass Facility (e.g., GNU libg++)
(3) Parameterized Types
(4) void Pointer Method
Preprocessor Macros
genclass  Note, methods 1,3 apply to homogeneous
void Pointer Method collections; method 4 allows heterogeneous
void Pointer Example collections
1 2

Container Class Objectives Container Class Objectives


 Application Independence (cont'd)
{ Transparently reuse container class code for  Type Safety
various applications
{ Insure that the collections remain type safe
 Ease of Modi cation  This is easy for parameterized types, harder
for void pointers :::

{ Relatively easy to extend classes to t smoothly


into a new application
 Run-Time Eciency and Space Utiliza-
tion
 Ease of Manipulation { Di erent schemes have di erent tradeo s
{ Implementation must hide representation de- e.g., extra indirection vs exibility
tails, e.g., iterators 

3 4
Object-Oriented Class Library
Architecture
 Two general approaches are tree vs forest Object-Oriented Class Library
(di er in their use of inheritance): Architecture (cont'd)
Tree: create a single rooted tree of classes de-
rived from a common base class, e.g., object
{ e.g., standard Smalltalk libraries or NIHCL Object

Forest: a collection of generally independent classes Numeric Container Shape


available for individual selection and use Sorted Unsorted
{ e.g., GNU libg++ library, Borland C++ class
library, Booch components, Rogue Wave, Vector Stack Circle Square
USL Standard components
Binary Bag Rectangle
Srch Tree
 Tradeo s:
1. Uniformity (Tree) vs exibility (Forest)  Tree-based class library
2. Sharing (Tree) vs eciency (Forest)
{ Forest classes do not inherit unnecessary func-
tions
5 6

Parameterized Types
 Parameterized list class
Object-Oriented Class Library
template <class T>
Architecture (cont'd) class List f
public:
List (void): head (0) fg
void prepend (T &item) f
Node<T> *temp =
Hash new Node<T> (item, this->head );
Table this->head = temp;
Splay Tree g
/* */
private:
:::
Vector
template <class T>
Binary class Node f
Srch Tree Queue private:
T value ;
Node<T> *next ;
Stack Bag public:
Node (T &v, Node<T> *n)
: value (v), next (n) fg
g;
Node<T> *head ;
 Forest-based class library g;

int main (void) f


List<int> list;
list.prepend (20);
// :::
g
7 8
Preprocessor Macros
 Stack example (using GNU g++)
Parameterized Types (cont'd) #ifndef stack h
#de ne stack h
 Parameterized Vector class #de ne name2(a,b) gEnErIc2(a,b)
#de ne gEnErIc2(a,b) a ## b
#de ne Stack(TYPE) name2(TYPE,Stack)
template <class T = int, int SIZE = 100>
class Vector f #de ne StackDeclare(TYPE) \
public: class Stack(TYPE) f \
publicStack(TYPE)
:\
Vector (void): size (SIZE) fg (size t size): size (size) f \
T &operator[] (size t i) f this
this ->bottom = new TYPE[size]; \
->top = this->bottom + size; \
return this->buf [i]; g\
g TYPE pop (void) f \
private: g\
return *this->top ++; \
T buf [SIZE]; void *push (TYPE item) f \
--this->top = item; \
size t size ; g\
g; bool return
is empty (void) f \
this+->this
top == this->bottom \
int main (void) f ->size ; \
Vector<double> d; // 100 doubles g\
Vector<int, 1000> d; // 1000 ints bool return
is full (void) f \
this->bottom == this->top ; \
d[10] = 3.1416; g\
g ~Stack(TYPE) (void) f delete this->bottom ; g \
private :\
TYPE *bottom ; \
TYPE *top ; \
size t size ; \
g
#endif
9 10

Preprocessor Macros (cont'd) genclass


 Stack driver  Technique used by GNU libg++
#include <stream.h> { Uses sed to perform text substitution
#include "stack.h"
StackDeclare (char);
typedef Stack(char) CHARSTACK; sed -e "s/<T>/$T1/g" -e "s/<T&>/$T1$T1ACC/g"
int main (void) f
const int STACK SIZE = 100;
CHARSTACK s (STACK SIZE);  Single Linked List class
char c;
cout << "please enter your name..: ";
class <T>SLList f
while (!s.is full () && cin.get (c) && c != '\n') public:
s.push (c); <T>SLList (void);
<T>SLList (<T>SLList &a);
cout << "Your name backwards is..: "; ~<T>SLList (void);
while (!s.is empty ()) <T>SLList &operator = (<T>SLList &a);
cout << s.pop (); int empty (void);
cout << "\n"; int length (void);
g void clear (void);
Pix prepend (<T&> item);
 Main problems: Pix append (<T&> item);
/* */
:::

protected:
(1) Ugly ;-) <T>SLListNode* last ;
(2) Code bloat g;
(3) Not integrated with compiler
11 12
void Pointer Method void Pointer Example
 General approach:  One example application is a generic ADT
List container class. It contains four basic
{ void * pointers are the actual container ele- operations:
ments
1. Insertion
{ Subclasses are constructed by coercing void *
elements into pointers to elements of interest { add item to either front or back
2. Membership
 Advantages: { determine if an item is in the list
1. Code sharing, less code redundancy
3. Removal
2. Builds on existing C++ features (e.g., inheri-
tance) { remove an item from the list
4. Iteration
 Disadvantages: { allow examination of each item in the list
1. Somewhat awkward to design correctly (without revealing implementation details)
2. Inecient in terms of time and space (requires
dynamic allocation)  The generic list stores pointers to elements,
along with pointers to links
3. Reclamation of released container storage is
dicult (need some form of garbage collec- { This allows it to hold arbitrary objects (but
tion) watch out for type-safety!!)
13 14

void Pointer Example (cont'd)


 Generic List.h
#ifndef Generic List  Generic List.h (cont'd)
#de ne Generic List
class List f protected:
public: // used by subclasses for implementation
List (void); void add to end (void *);
~List (void); void add to front (void *);
void remove current (void); Node *current value (void);
// Used as iterators
:::
void *current (void);
void reset (void); bool includes (void *);
void next (void); void *remove (void *);
protected:
class Node f // important to make match virtual!
friend List; virtual bool match (void *, void *);
public: private:
Node (void *, Node *n = 0); Node *head ;
~Node (void);
void add to front (void *); Node *iter ; // used to iterate over lists
g;
void add to end (void *);
Node *remove (void *);
private:
void *element ; // Pointer to actual data
Node *next ;
g;
15 16
 Generic List.C
 Generic List.h (cont'd) // Node methods
inline List::Node::Node (void *v, List::Node *n)
: element (v), next (n) fg
// Iterator functions
inline List::Node *List::current value (void) f inline List::Node::~Node (void) f
return this->iter ; if (this->next ) // recursively delete the list!
g delete this->next ;
g
inline void List::reset (void) f
this->iter = this->head ; inline void List::Node::add to front (void *v) f
g this->next = new List::Node (v, this->next );
g
inline void *List::current (void) f void List::Node::add to end (void *v) f
if (this->iter ) if (this->next ) // recursive!
return this->iter ->element ; this->next ->add to end (v);
else else
return 0; this->next = new List::Node (v);
g g
List::Node *List::Node::remove (void * v) f
inline void List::next (void) f if (this == v)
this->iter = this->iter->next ; return this->next ;
g else if (this->next ) // recursive
this->next = this->next ->remove (v);
return this;
g
17 18

 Generic List.C (cont'd)


 Generic List.C void List::remove current (void) f
if (this->head == this->iter )
// List methods this->head = this->iter ->next ;
void List::add to front (void *v) f else
this->head = new List::Node (v, this->head ); this->head = this->head ->remove (this->iter );
g this->iter ->next = 0;
void List::add to end (void *v) f delete this->iter ; // Deallocate memory
if (this->head ) // recursive! this->iter = 0;
this->head ->add to end (v); g
else
this->head = new List::Node (v); void *List::remove (void *v) f
g for (this->reset (); this->current (); this->next ())
bool List::includes (void *v) f if (this->match (this->current (), v)) f
// Iterate through list void *fv = this->current ();
for (this->reset (); this->current (); this->next ()) this->remove current();
// virtual method dispatch! return fv;
if (this->match (this->current (), v)) g
return true; return 0;
return false; g
g
bool List::match (void *x, void *y) f inline List::List (void): head (0), iter (0) fg
return x == y;
g
List::~List (void) f
if (this->head ) delete this->head ; // recursive!
g
19 20
void Pointer Example (cont'd)  Card.h
 Card.h inline int Card::rank (int) f return this->rank ; g
inline Card::Suit Card::suit (void) f return this->suit ; g
#include "Generic List.h" inline bool Card::operator == (Card &y) f
class Card f return this->rank () == y.rank ()
friend class Card List; && this->suit () == y.suit();
public:
enum Suit f g
SPADE = 1, HEART = 2, CLUB = 3, DIAMOND = 4
g; inline void Card::print (ostream &str) f
enum Color f BLACK = 0, RED = 1 g; str << "suit " << this->suit ()
Card (int r, int s); << "rank " << this->rank () << endl;
int rank (void); g
Suit suit (void);
Color color (void); inline Card::Card (int r, Card::Suit s)
bool operator == (Card &y); : rank (r), suit (s) fg
void print (ostream &);
private: inline Card::Color Card::color (void) f
int rank ; return Card::Color (int (this->suit ()) % 2);
Suit suit ; g
g;

21 22

 Card List.h
#include "Card.h"
class Card List : public List f
public:
void add (Card *a card) f
List::add to end (a card);  Card List.C
g
// Virtual method
Card *current (void) f bool Card List::match (void *x, void *y) f
return (Card *) List::current (); Card &xr = *(Card *) x;
g Card &yr = *(Card *) y;
// Calls Card::operator ==
int includes (Card *a card) f return xp == yp;
return List::includes (a card); g
g
void Card List::print (ostream &str) f
void remove (Card *a card) f for (this->reset (); this->current (); this->next ())
List::remove (a card); this->current ()->print (str);
g g

void print (ostream &);


protected:
// Actual match function used by List!
virtual bool match (void *, void *);
g;
23 24
 main.C
#include "Card.h"
int main (void) f
Card List cl;
Card *a = new Card (Card::HEART, 2);
Card *b = new Card (Card::DIAMOND, 4);
Card *c = new Card (Card::CLUB, 3);
cl.add (a); cl.add (b); cl.add (c); cl.add (b);
cl.print (cout);
if (cl.includes (new Card (Card::DIAMOND, 4)))
cout << "list includes 4 of diamonds\n";
else
cout << "something's wrong!\n";
cl.remove (new Card (Card::CLUB, 3));
cl.print (cout);
return 0;
g

 Main problem:
{ Must dynamically allocate objects to store into
generic list!
 Handling memory deallocation is dicult with-
out garbage collection or other tricks :::

25

Вам также может понравиться