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

COLLECTIONS IN TURBO C++_

by Bruce Eckel

[LISTING ONE]

// COLLECT.CPP : collection example, with multiple inheritance and


// pointers to members.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct item {
virtual ~item() {} // so collection can properly destroy what it holds
};

// Suppose we have a pre-existing class to hold items:


class collection {
// in 2.0, "holder" is a global name. In 2.1, it's hidden:
struct holder {
holder * next; // link to next holder
item * data; // pointer to actual data
holder(holder * nxt, item * dat) // constructor
: next(nxt), data(dat) {}
} *head, *cursor;
public:
// initialize an empty list:
collection() : head((holder *)NULL), cursor((holder *)NULL) {}
// clean up the list by removing all the elements:
~collection() {
cursor = head;
while(cursor) { // while the list is not empty ...
delete cursor->data; // delete the current data
head = cursor->next; // head keeps track of where the next holder
is
delete cursor; // delete the current holder
cursor = head; // move to the next holder
}
}
// Paste a new item in at the top (this is tricky):
void add(item * i) { head = new holder(head, i); }
// reset() and next() return the current item or null, for the list's
end:
item * reset() { // go back to the top of the list
cursor = head;
// the list may be empty; only return data if cursor isn't null
return cursor ? cursor->data : (item *)NULL;
}
item * next() {
// Only move forward if cursor isn't null:
if(cursor) cursor = cursor->next;
// only return data if cursor isn't null:
return cursor ? cursor->data : (item *)NULL;
}
};

// Now suppose we have a second pre-exising class to hold words,


// keep track of word counts, and print itself in 2 ways:
class word {
char * w;
int count;
public:
word(char * wd) : count(1) {
w = new char[strlen(wd) + 1]; // allocate space for word
strcpy(w,wd); // copy it in
}
~word() {
printf("%s : %d occurrences\n", w, count);
delete w; // free space for word
}
int compare(char * testword) {
int match = !strcmp(w, testword);
if(match) count++; // count testword if it matches
return match;
}
void print1() { printf("%s\n", w); } // 1 per line
void print2();
};

// Zortech 2.06 and cfront 2.0 wouldn't allow the following


// function as an inline; Turbo C++ would.
void word::print2() { // print several words per line
static p1cnt; // count words on a line
const words_per_line = 7;
printf("%s ", w);
if(++p1cnt % words_per_line) return;
putchar('\n'); // only when remainder is 0
}

// What if we want to make a collection of words? Multiple


// Inheritance to the rescue:
class worditem : public item, public word {
public:
worditem(char * wrd) : word(wrd) {}
};

// now we can create a collection of worditems. Here's an array


// of words to put in our collection:
char * words[] = { "this", "is", "a", "test", "of", "worditem" };

#ifdef TEST1
main() {
collection c;
for(int i = 0; i < sizeof(words)/sizeof(words[0]); i++)
c.add(new worditem(words[i]));
// NOTE: Zortech C++ 2.06 doesn't work here.
}
#endif // TEST1

// But now we want to count instances of words. We need to modify the


// collection class so it conditionally adds a word, or just counts it
// if it already exists:

class wordcounter : public collection {


public:
// Customize for worditems (no overhead):
void add(worditem * wi) { collection::add(wi); }
worditem * reset() { return (worditem *)collection::reset(); }
worditem * next() { return (worditem *)collection::next(); }
void add_or_count(char * newword) {
worditem * cur = reset();
while(cur) {
// if found, increment the count and quit the search:
if(cur->compare(newword)) return;
cur = next();
}
// at this point, we didn't find it, so add it to the list:
add(new worditem(newword));
}
// Pointers to members (Zortech 2.06 doesn't support this):
void apply(void (word::*pmf)()) {
worditem * wit = reset();
while(wit) { // do while list is not empty
(wit->*pmf)(); // dereference member function pointer
wit = next(); // get next list element
}
}
};

char * words2[] = { "this", "this", "is", "a", "test", "test", "test" };

#ifdef TEST2
main() {
wordcounter wc;
for(int i = 0; i < sizeof(words2)/sizeof(words2[0]); i++)
wc.add_or_count(words2[i]);
// Now "apply" two different functions to the list:
wc.apply(&word::print1);
wc.apply(&word::print2); putchar('\n');
}
#endif // TEST2

// Now, for fun, let's use this class to count the keywords and
// identifiers in a C++ program. Try this program on itself:
// collect < collect.cpp > count
// Look up strstr(), strchr() and strtok() in your ANSI C
// library guide.

const char * delimiters = " \t#/(){}[]<>.,;:*+-~!%^&=\\|?\'\"";


const char * digits = "0123456789.";

#ifdef TEST3
main() { // use i/o redirection on the command line.
wordcounter symbol_table;
char buf[120];
while (gets(buf)) { // get from standard input
if(*buf == '#') continue; // ignore preprocessor lines
// strip all quoted strings in the line:
char * quote = strchr(buf, '\"'); // find first quoted string
while(quote) {
if(quote[-1] == '\\') break; // for \" literal quote
*quote++ = ' '; // erase quote
while(*quote != '\"' && *quote != 0)
*quote++ = ' '; // erase contents of string
*quote = ' '; // erase ending quote
quote = strchr(quote, '\"'); // look for next quoted string
}
char * cmt = strstr(buf, "//"); // C++-style comments only
if(cmt) *cmt = 0; // strip comments by terminating string
puts(buf); // Look at the modified string
char * token; // strtok uses delimiters to find a token:
if((token = strtok(buf, delimiters)) != NULL){ // first strtok call
if(strcspn(token, digits)) // ignore constants
symbol_table.add_or_count(token);
// subsequent strtok calls for the same input line:
while((token = strtok(0, delimiters)) != NULL)
if(strcspn(token, digits)) // ignore constants
symbol_table.add_or_count(token);
}
} // print the list in 2 ways, using pointers to members:
symbol_table.apply(&word::print1);
symbol_table.apply(&word::print2); putchar('\n');
} // results are output by the destructor calls
#endif // TEST3

[Example 1: Macro that puts void at the beginning of a line, then


returns to the point where you invoked it.]

macro InsertVoid
SetMark(0); /* save our place */
LeftOfLine;
InsertText("void ");
MoveToMark(0); /* restore the place */
end; /* end of macro InsertVoid */

Alt-V : InsertVoid; /* bind to key */

[Example 2: Typical collection]

item * i = c.reset();
while(i) {
// do something
i = c.next();
}

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