You are on page 1of 12

Dr. Dobb's | Object-Oriented Programming In C | July 01, 1990 http://www.drdobbs.com/article/print?articleId=184402190&siteSecti...

Object-Oriented Programming In C

July 01, 1990
URL:http://www.drdobbs.com/object-oriented-programming-in-c/184402190

David Brumbaugh is a software developer at Advanced Information Services, Inc. in Peoria IL. He has a B.A. in computer information science from Judson
College in Elgin, IL. He has been programming in C since 1985. He can be contacted at Computer Express BBS, (309) 688-9789, 1220-2400 Baud, 8,1,N
in the C Language Questions folder.

C programmers have been using something like object oriented programming for years. They called it good modularity.

The classic example of "object-oriented C" is the standard FILE structure and its family of functions fopen, fclose, fread, fwrite, fprintf, etc. Only the
"methods" of the file object, fopen etc., access the members of FILE.

The FILE functions are examples of good, modular, manageable code. A more accurate term for this type of programming is "structure driven". Structure-
driven programs consist of data structures and functions that support them. The difference may only be semantic, but FILE objects don't have any
allowance for inheritance or polymorphism. Structure members and functions that operate on them are not encapsulated into a single object.

Adding More OOPness

This article describes a technique which adds inheritance, polymorphism, and encapsulation to the familiar structure-driven style. The steps of this
technique (listed in Table 1) are chosen to work with a particular implementation of inheritance.

Consider the structures:

struct s1
{ int x;
int y;
};
struct s2
{ int x;
int y;
int z;
};

Suppose there is a structure of type s2 and a pointer to type s1.

struct s1 *s1p;
struct s2 s2s;
s1p = &s2s;

In almost all C compilers, s1p->x would be the same as s2s.x, and s1p->y would be the same as s2s.y. You could say that structure s2 inherited x and y
from structure s1. Any function that expected a pointer to s1 could instead take a pointer to s2 and could correctly address x and y and safely ignore z.

Listing 1 illustrates how to utilize this technique in an easy, self-documenting way. By using #define to define a class, S1, and using this definition to
describe a subclass, S2, we assure that any changes to the S1_CLASS definition are automatically reflected in its subclass S2_CLASS at compile time.

An object is an instance of a class. In Listing 1, C's typedef permits objects to be declared.

Coding Conventions

I observe certain conventions when writing methods for this OOP technique.

The first argument to a method is always a pointer to the object calling the method. Many C++ translators do the same thing.
The first argument to a method is always named this, clarifying references to the calling object.
All program code for a particular class is always in the same .c file. Methods are given exactly the same function name as the pointers to those
methods. These functions are static, so they don't interfere with other functions of the same name in other files.
When writing an abstract base class's methods, write functions for methods that are defined to be subclass implemented. You may simply print a
message to the effect that the method is not available.
All constructors are named in the form new_CLASS(). The only arguments in constructors are for initialization. The template in Listing 2 is the basis
for all constructors. If the constructor is a base class, remove all SUPER_CLASS references from this template.
Destructors have a format that reverses the inheritance process. Destructor names have the form destroy_CLASS(). The first, and usually only,
argument is a pointer to the object being destroyed. The second template in Listing 2 is the general form of a destructor.

1 of 12 2/15/2017 4:31 PM

Some methods. modular.h adds a PHONE_ENTRY pointer to hold the list and a sort method to maintain the list in a sorted order. This technique does not require any data structures other than those required by the objects. What goes into the list is determined by the application. Sometimes these lists are arrays.c in Listing 3.DRAW. This example will develop a LIST_CLASS.c all methods not previously written are completed. The resulting syntax of this technique is closer to C+ + than White's. Pinnacle is built around the relational model. The curr attribute is the index of the current member.radius). A working buffer is also added for convenience. seek may not contain the most efficient algorithm for all list types. The list will have a "top" and an "end". In Listing 5 phlist1. 1990 http://www. Prior Art Eric White described another technique for writing "truly" object-oriented programs in the February issue of The C Users Journal. This example will be a simple phone list with a first name.times they are views of database records.draw(radius). If the list is temporary. First.c show how a dynamic array can be used to implement the LIST_CLASS.h and pinlist. fulfilling the 00 requirement that a subclass can be used in place of a superclass. There will be the concept of a "current" member. The trial diskette will suffice if you want to try these programs yourself. For the phone list. The selector window is used as a menu and chooses a record from a data table. but a free trial disk is available from Vermont Database Corporation. so a list is defined to be from one table in a database. From this abstract LIST_CLASS. can be written by utilizing other methods. A PHONE_ENTRY structure will be used to hold the data. Classes and subclasses are defined using C's #deine directive. an issue not directly addressed by White. I chose the Pinnacle library for two reasons. such as seek and total_members. In phlist. Second. arrylist. The first example is C++. "structure-driven" library. In Listing 3 list. An Example Application Many applications need to deal with lists. and tot_members is the number of members in the array. like White's. Compare the following three object-oriented methods of having a circle draw itself. I developed this object when I needed a selector window. The list will be maintained in a last name. Column use is application dependent and will be specified in the more concrete subclass. There are some differences between the technique I am suggesting and his. This is where the OO advantage comes in. The second reason is availability. The goal is to create a class that will allow an application to have uniform access to all types of lists.com/article/print?articleId=184402190&siteSecti. more concrete classes need to be made. Methods are inherited from superclasses in a subclass's constructor. 1. sometimes they are linked lists.. I was able to add an OO layer to it by encapsulation. it is a good.. There is no specific CLASS structure and no specific OBJECT structure like in White's technique. The second example uses the Pinnacle relational DBMS to hold the elements. last name and phone number for each entry. defines an abstract base class that more concrete classes can inherit from. This technique does not require the use of any additional functions such as White's message function. so it can polymorphed later if necessary. even if it is only a physical order. and I did not want to have to make a large mental jump to get from C+ + to code I could use. In Listing 4. Most of the OOP code I have seen in articles has been in C++. Dobb's | Object-Oriented Programming In C | July 01.c the constructor 2 of 12 2/15/2017 4:31 PM . The concrete classes must address two issues. what goes into the list. how the list is implemented. This similarity to C++ was important to me.drdobbs. circle. Pinnacle is a commercial product. In phlist2. a database of some sort may be a logical choice. 3. The same can be said of total_members. first name order.Dr. I have chosen to use two list handling methods to illustrate this technique. but no function is required to register new methods. 2.h in Listing 7 defines which columns from the table will be used. The list will be ordered in some way. It defines the types of things you would normally do with a list.c in Listing 6 show how a database package can be used to make LIST_CLASS more concrete. Scope is used to supply a rudimentary form of polymorphism. without the programmer having to concern himself with how the list is stored. some. Two new attributes are added to the LIST_CLASS. message(&circle. First. phlist2. and the third uses the technique described here. not to the application. The SELECTOR object had a LIST pointer as a member. The methods in Table 2 are common to all lists.h and arrylist. Examine list. a dynamic array or linked list may be more practical. There are no separate constructors and destructors for CLASS and OBJECT. the changes are made within the class. Constructors and destructors have more responsibility for inheritance and polymorphism. The default methods for total_members and seek were not efficient so these methods are polymorphed. the second uses White's technique. Concrete sub-classes of ARRAY_LIST_CLASS and PINNACLE_LIST_CLASS were both used by the SELECTOR.radius). pinlist.h. circle->draw(circle. If a decision is made to change from a linked list to a database. The first example uses a dynamic array to hold the elements of the list. How to implement the list is a design decision.

The output generated by this program is also identical in both cases.sizeof(CLASS)). testlist.. /* Inherit everything you can from the superclass */ memmove(this. Dobb's | Object-Oriented Programming In C | July 01. this technique isn't strictly portable because it assumes that identical members within different structures are arranged uniformly.0 to test the code for this article. If a superclass contains a design bug.c. defines which table and database to use. is the same for both implementations. 1990 http://www. \ int (*read_x)(). and I have successfully tested the technique with two MS-DOS compilers and one UNIX compiler. I have had C++ translators change the names of the functions I call and cause link errors with outside libraries. Instead. typedef struct s1 { S1_CLASS } S1. \ int (*read_y)(). /* Construct super class */ s = new_SUPER_CLASS(). To use this technique on a different compiler. rather than the exception. CLASS *this. With this technique. I used Turbo C 2. Officially. \ typedef struct s2 { S2_CLASS } S2. Finally.*/ return(this). even when overridden." I could then assign any type of pointer to any other type of pointer and still keep some prototyping. the technique is intended to allow a programmer to experiment with object-oriented techniques without having to invest in learning a new language. \ int (*read_z)(). However. allocate etc. Conclusion The technique presented here is not intended to replace object-oriented languages such as C++. There are enough differences between C++ and C to make many existing libraries useless. Listing 1 #define S1_CLASS int x. \ int y. Bugs are inherited with features. Acknowledgements I would like to thank Bob Pauwels and Mike Yocum of Advanced Information Services for their input to this article. Data encapsulation makes the internals of the objects transparent. Some prototyping may be sacrificed in inheritance. especially if you change the prototype from one class level to the next.com/article/print?articleId=184402190&siteSecti. There are some advantages to using this technique over C++ or some other OOL. There are a number of advantages to using this technique to write programs. Code and data are changed in an organized way through inheritance.Dr. the arrangement of members within a structure is implementation dependent. Changing to any OOP technique carries some disadvantages. you may have to remove the prototypes entirely. Listing 8.drdobbs. the arrangement assumed here is the rule. C++ constructors are more automatic. Maintenance and enhancement are easier because of this encapsulation. /* Allocate memory for this object */ this = calloc(1.s. the whole class hierarchy is affected. I used the sample database provided with Pinnacle. There are some disadvantages to using this technique over C++. /* Inialize attributes here. To keep some prototyping I turned off the ANSI warning "Suspicious pointer conversion. complicating the debugging of large class hierarchies. or an inherited technique contains a bug.sizeof(CLASS). Listing 2 CLASS *new_CLASS() { SUPER_CLASS *s. Open files. #define S2_CLASS S1_CLASS \ int z. It allows you to realize most of the benefits associated with OOP. I can use an object-oriented style and still have full access to all the C functions currently in use. There is more overhead when using a derived class because all the code from its superclasses needs to be linked into the program. /* Assign methods to object */ this->f1 = f1.. I have seen examples of library functions having names that are C++ reserved words. This is a significant advantage if one considers the thousands of dollars and man-hours invested in existing libraries. /* We're done with the superclass's memory */ free(s). 3 of 12 2/15/2017 4:31 PM .

h> #include "list. getch(). \ (*display)(struct list*). /* Close any files specific to this class: */ fclose(this->file). #define TRUE 1 #define FALSE 0 /* -------------------.. } static void seek(LIST *this. 1990 http://www. } break.com/article/print?articleId=184402190&siteSecti. Dobb's | Object-Oriented Programming In C | July 01. \ void *(*current)(struct list *).Dr. \ (*replace_member)(struct list *. \ (*seek)(struct list *. LIST. int). void *). LIST *new_list(). this->next(this).. \ (*end)(struct list *).C ------------------*/ #include <stdio. } void destroy_SUPER_CLASS(SUPER_CLASS *this) { free(this). \ (*next)(struct list *). \ (*is_empty)(struct list*). \ (*add_member)(struct list*. \ (*at_end)(struct list*).h" static void not_valid() { fprintf(stderr. /* Call the superclass's destructor */ destroy_SUPER_CLASS(this). this->next(this). long where. void *).h> #define LIST_CLASS unsigned (*at_top)(struct list*). } } else { for(count = 0.). ++count) { if ( this->at_end(this) ) break. ++count) { if ( this->at_end(this) ) break.h> #include <string.. int start) { long count. this->prev(this).drdobbs.List. \ long (*total_members)(struct list *). \ (*find)(struct list *. for (count = 0.h> #include <stdlib. } static unsigned is_empty(LIST *this) { return( this->total_members(this) == 0L). switch(start) { case SEEK_SET: this->top(this). case SEEK_CUR: if (where > 0) { for (count = 0. \ void (*prev)(struct list*). } Listing 3 /* -------------------. \ (*top)(struct list *). ++count) { if (this->at_top(this) ) break. long.h> #include <stdlib. count < where.*/ #include <stdio. count < where. count > where. typedef struct list { LIST_CLASS } LIST. } void destroy_CLASS(CLASS *this) { /* Free any specific data: */ free(this->p). \ (*tell)(struct list *). } 4 of 12 2/15/2017 4:31 PM . ."Operation is not valid for this list\n").H-----------------.. destroy_list(LIST *).

this->top(this).h" static long total_members(ARRAY_LIST *this) { return((long) this->tot_members).C ------------------------*/ #include "arrylist. for(count = 0. do { if ( ! this->at_end(this) ) { ++count. } static void prev(ARRAY_LIST *this) { if (this->curr > 0) --(this->curr). /* Assign Methods */ this->at_top = not_valid. if (this == NULL) return(NULL).. ++count) { if ( this->at_top(this) ) break. return(count).h> #define ARRAY_LIST_CLASS LIST_CLASS \ /* Index of current member */ int curr. case SEEK_END: this->end(this). thisone = this->tell(this). this->tell = not_valid.com/article/print?articleId=184402190&siteSecti. this->find = not_valid. count = 0. Dobb's | Object-Oriented Programming In C | July 01. thisone. count. } destroy_list{LIST *this) { free(this). } } static long total_members(LIST *this) { long thisone.SEEK_SET). this->end = not_valid. destroy_array_list(ARRAY_LIST *).drdobbs. this->seek{ this. this->at_end = not_valid. this->seek = seek.Dr. } break. this->current = not_valid. } 5 of 12 2/15/2017 4:31 PM . this->total_members = total_members. this->next = not_valid. typedef struct array_list { ARRAY_LIST_CLASS } ARRAY_LIST. 1990 http://www. this->prev = not_valid. this->replace_member = not_valid. count > where. } static unsigned at_end(ARRAY_LIST *this) { return(this->curr == this->tot_members). } break. \ /* Total members in array */ int tot_members. this->display = not_valid. this->add_member = not_valid. } Listing 4 #include "list. /*-----------------. this->is_empty = is_empty. ARRAY_LIST *new_array_list(). /* Allocate Memory for this Object */ this = calloc(1. this->next(this). this->prev(this).ARRYLIST.. return(this). this->top = not_valid.sizeof(LIST)). } LIST *new_list() { LIST *this. } } while( ! this->at_end(this) ).h" #include <alloc. } static unsigned at_top(ARRAY_LIST *this) { return(this->curr == 0).

if (l == NULL) return(NULL).. LIST *1. PHONE_LIST *new_phone_list(). this->top = top. return(NULL). } memmove(this.H ---------------*/ #include "arrylist. break. } } break. phone_no[14]. } static void seek(ARRAY_LIST *this. long where. first_name[11]. /* -----------------.h" typedef struct phone_entry { char last_name[21]. l = new list().(int) where) > 0) { this->curr -= (int) where. this->next = next.PHLIST1.PHLIST1. } PHONE_ENTRY. } static void end(ARRAY_LIST *this) { this->curr = this->tot_members . int from) { switch(from) { case SEEK_SET: if (where < this->tot_members) this->curr = (int) where. typedef struct phone_list { PHONE_LIST_CLASS } PHONE_LIST. Dobb's | Object-Oriented Programming In C | July 01. } Listing 5 /* ----------------. } } static void top(ARRAY_LIST *this) { this->curr = 0. this->prev = prev. #define PHONE_LIST_CLASS ARRAY_LIST_CLASS \ PHONE_ENTRY *data..sizeof(ARRAY_LIST)).(int) where. } static long tell(ARRAY_LIST *this) { return(this->curr). free(l). this->end = end. if (this == NULL) { destroy list(l). this->at_end = at_end. \ void (*sort)(struct phone_list *).1. } ARRAY_LIST *new_array_list(void) { ARRAY_LIST *this.Dr. this->total_members = total_members. this = calloc(l. this->seek = seek. return(this). this->at_top = at_top. } destroy_array_list(ARRAY_LIST *this) { destroy_list(this). static void next(ARRAY_LIST *this) { if (this->curr < (this->tot_members)) ++(this->curr). } break. case SEEK_CUR: if (where > 0) { if ( (this->curr + (int) where) < this->tot_members ) { this->curr += (int) where. void destroy_phone_list(PHONE_LIST *). this->tell = tell. 1990 http://www.C ---------------. } } else { if ((this->curr .sizeof(LIST)). case SEEK_END: if (where <= this->tot_members) { this->curr = this->tot_members .l.com/article/print?articleId=184402190&siteSecti.drdobbs.*/ 6 of 12 2/15/2017 4:31 PM .

} pe = this->current(this). pe2->first_name)).%-13s\n". } static unsigned find(PHONE_LIST *this. 1990 http://www. else if (stricmp(pe->last_name. this->curr = orig. } static display(PHONE_LIST *this) { PHONE_ENTRY *pe. sizeof(PHONE_ENTRY). "\nMemory Error in Function %s <Press a Key>\n". } else this->next(this). ++(this->tot_members). return(FALSE). } } static void add_member(PHONE_LIST *this.h" #include <string. pe->first_name. 7 of 12 2/15/2017 4:31 PM . PHONE_ENTRY *pe2) { int ret. (size_t) this->tot_members. if ( stricmp(pe->last_name. pe.sizeof(PHONE_LIST)). al = new_array_list(). int orig.drdobbs. sizeof(PHONE_ENTRY)). ret = stricmp(pe1->last_name. } static int pe_comp(PHONE_ENTRY *pe1. PHONE_ENTRY *pe) { if (this->data != NULL) memmove(this->data + this->curr. sizeof(PHONE_ENTRY) * (this->tot_members + 1)).. %-10s .h> static void phone_list_memory_error(char *fun) { fprintf(stderr. } PHONE_LIST *new_phone_list() { ARRAY_LIST *al. } static PHONE_LIST *current(PHONE_LIST *this) { if (! this->at_end(this) && this->data != NULL) return(this->data + this->curr).sizeof(PHONE_ENTRY)). this->sort(this). if (pe ! = NULL) { printf("%-20s.Dr. } static void replace_member(PHONE_LIST *this. PHONE_ENTRY *pe) { this->data = realloc(this->data. if (this->data == NULL) phone_list_memory_error("phone_list: add_member"). PHONE_LIST *this. return(ret). orig = this->curr. } static sort(PHONE_LIST *this) { qsort(this->data. pe->last_name. pe->phone_no). pe = this->current(this). return(FALSE). memmove(this->data + this->tot_members.com/article/print?articleId=184402190&siteSecti.srch_last_name) == 0) return(TRUE). if (ret == 0) return(stricmp(pe1->first_name. if (al == NULL) return(NULL). Dobb's | Object-Oriented Programming In C | July 01. exit(1).h> #include <stdlib.srch_last_name) == 0) return(TRUE). pe2->last_name).srch_last_name) > 0) { this->curr = orig. while(! this->at_end(this)) { pe = this->current(this). else return(NULL).. if ( stricmp(pe->last_name. pe. fun).h> #include <conio.char *srch_last_name) { PHONE_ENTRY *pe. #include "phlist1. getch(). this = calloc(1. pe_comp).

} static unsigned at_top(PINNACLE_LIST *this) { return(this->is_at_top). return(NULL). PINNACLE_LIST *new_pinnacle_list(char *database. this->is_at_top = TRUE. \ /* Boolean flags*/ unsigned is_at_top. return(this).C -----------------. DBNEXT)) this->is_at_bottom = FALSE.al. thisrow = DB_CurrentRow(this->table). /*-----------------. this->current = current.h" static long total_members(PINNACLE_LIST *this) { return((long) DB_CountRows(this->table)).h" #include "list.H-------------------.. this->find = find.*/ #include "pinlist. long position = 0L. this->replace_member = replace_member. if (this->total_members(this) > 1) this->is_at_bottom = FALSE. } static long tell(PINNACLE_LIST *this) { DBROWID thisrow.PINLIST. is_at_bottom.. } static unsigned at_end(PINNACLE_LIST *this) { return(this->is_at_bottom). checkrow. this->display = display. char *table).h" #define PINNACLE_LIST_CLASS LIST_CLASS \ /* Pinnacle Database Object */ DB db.DBNEXT).drdobbs. 8 of 12 2/15/2017 4:31 PM . if (this->total_members(this) > 1) this->is_at_top = FALSE. DBPREVIOUS)) this->is_at_top = FALSE. this->is_at_top = FALSE. if (this == NULL) { destroy_array_list(al). } static void prev(PINNACLE_LIST *this) { if (DB_NextRow(this->table. 1990 http://www.PINLIST. this->is_at_bottom = TRUE. } memmove(this. if (this->total_members(this) > 1) this->is_at_bottom = FALSE. this->add_member = add_member. this->sort = sort. free(al). destroy_array_list(this). } Listing 6 /* ----------------. } static void next(PINNACLE_LIST *this) { if (DB_NextRow(this->table.com/article/print?articleId=184402190&siteSecti.Dr. Dobb's | Object-Oriented Programming In C | July 01.*/ #include "pinnacle. DB_NextRow(this->table. } void destroy_phone_list(PHONE_LIST *this) { if (this->data) free(this->data). this->top(this). if (this->total_members(this) > 1) this->is at bottom = TRUE.sizeof(ARRAY_LIST)). else this->is_at_top = TRUE. typedef struct pinnacle_list { PINNACLE_LIST_CLASS } PINNACLE_LIST. } static void top(PINNACLE_LIST *this) { DB_FirstRow(this->table). } static void end(PINNACLE_LIST *this) { DB_ForAllRows(this->table). \ /*Pinnacle Database Table */ DBTAB table.

DBNEXT).%-13s\n". return(found). PHONE_LIST *new_phone_list().last_name. \ DBCOL last. return(NULL). if (l == NULL) return(NULL). } static unsigned find(PHONE_LIST *this. this->at_end = at_end. } return(position). this->table = DB_Table(this->db.com/article/print?articleId=184402190&siteSecti. typedef struct phone_list { PHONE_LIST_CLASS } PHONE_LIST. sobj = DB_SearchObject(this->db."rw".sizeof(PINNACLE_LIST)).*/ #include "phlist2. l = new_list().this->pe. String. this->prev = prev. } destroy_pinnacle_list(PINNACLE_LIST *this) { DB_Close(this->db). this->tell = tell. this->db = DB_Open(datab.first_name. while(checkrow != thisrow) { ++position.PHLIST2.. srch_l_name. found = DB_FindNext(this->last. Dobb's | Object-Oriented Programming In C | July 01.DB_GetString(this->phone)). checkrow = DB_CurrentRow(this->table). /* ---------------. phone. void destroy_phone_list(PHONE_LIST *).PHLIST2.h> #include <stdlib. this->at_top = at_top. "==").drdobbs. first. this->pe.h" #include <string. exit(1).. } static display(PHONE_LIST *this) { strcpy(this->pe. #define PHONE_LIST_CLASS PINNACLE_LIST_CLASS \ PHONE_ENTRY pe.H --------------------.C -----------------------. "\nMemory Error in Function %s <Press a Key>\n". this->total_members = total_members. char *srch_l_name) { DBSEARCH sobj. lastfirst.Dr. } static void add_member(PHONE_LIST *this. destroy_list(this). free(l). LIST *l.DBNEXT).DB_GetString(this->first)). first_name[11].pe->last_name). DB_Free(sobj). this->top = top. printf("%-20s. return(this).phone_no.last_name.h> static void phone_list_memory_error(char *fun) { fprintf{stderr. fun).*/ #include "pinlist. this->pe. } memmove(this. PHONE_ENTRY *pe) { DB_AddRow)(this->table).h> #include <conio.first_name. this->next = next.DB_GetString(this->last)).l. } Listing 7 /* --------------------. getch(). this = calloc(1. } PHONE_ENTRY. strcpy(this->pe. 9 of 12 2/15/2017 4:31 PM .0).h" typedef struct phone_entry { char last_name[21].phone_no). 1990 http://www. DB_NextRow(this->table.char *table) { PINNACLE_LIST *this. if (this == NULL) { destroy_list(l). DB_PutString(this->last. strcpy(this->pe.table). phone_no[14].sobj. unsigned found. %-10s .sizeof(LIST)). this->end = end. checkrow = DB_CurrentRow(this->table). } PINNACLE_LIST *new_pinnacle_list(char *datab.

DB_PutString(this->first.pe->first_name). PHONE_LIST *this. this->current = current. {"Jones".{"Smith".sizeof(PHONE_LIST)). {"Kirk". static PHONE_ENTRY jane = {"Smith"."Last"). main() { PHONE_LIST *pe."456-7890"}."LastFirst").Kirk \n")."622-1701"}.first_name.com/article/print?articleId=184402190&siteSecti. ++x) pe->add_member(pe.pl. strcpy(this->pe. pe->top(pe). this = calloc(1. pe->top(pe).DB_GetString(this->phone)).pe->last_name). ************************************************************/ #include "phlist2. DB_OrderBy(this->lastfirst). pl = new_pinnacle_list("fonelist."Jim". PHONE_ENTRY *pe) { DB_PutString(this->last. return(this). pe->next(pe). 10 of 12 2/15/2017 4:31 PM . DB_PutString(this->phone.Program to test the list object using a phone list as an example. } Listing 8 /************************************************************ Testlist."Cyrano".last_name."874-2253"} }. for (x = 0. this->display = display. if (this == NULL) { destroy_pinnacle_list(pl).drdobbs. } memmove(this."First"). } printf("\n Finding . if (pe->find(pe. x < 5. pe = new_phone_list(). DB_PutString(this->phone. return(&(this->pe)). } static void replace_member(PHONE_LIST *this. return(NULL). printf("\nTesting Phone List:\n")."Phone").".pe->phone_no). this->last = DB_Column(this->table.. if (pe->find(pe."PhoneList"). 1990 http://www."Jane". Dobb's | Object-Oriented Programming In C | July 01."John"."Jon L. } void destroy_phone_list(PHONE_LIST *this) { destroy_pinnacle_list(this). this->replace_member = replace_member.DB_GetString(this->first)). strcpy(this->pe.c . DB_PutString(this->first. free(pl)."Kirk") == TRUE) pe->display(pe). printf("\n Trying to find McCoy \n").pe->phone_no).pe->first_name).{"Picard". printf("Replace John Smith with Jane\n").phone_no. if (pl == NULL) return(NULL)."456-0987"}.db"."Ben".. } PHONE_LIST *new_phone_list() { PINNACLE_LIST *pl.&test_data[x]). this->add_member = add_member. this->lastfirst = DB_Column(this->table. this->phone = DB_Column(this->table. printf("Current Member is :\n"). this->first = DB_Column(this->table. this->find = find. } static PHONE_ENTRY *current(PHONE_LIST *this) { strcpy(this->pe.sizeof(PINNACLE_LIST))."123/456-0987"}.Dr. int x.DB_GetString(this->last)). while( ! pe->at_end(pe) ) { pe->display(pe)."McCoy") == FALSE) printf("\nMcCoy not found\n")."622-1701"}.h" static PHONE_ENTRY test_data[] = { {"Able". pe->display(pe).

drdobbs. printf("Current member = %ld\n". c. Write methods common to the entire class hierarchy. Copy the superclass to this object.com/article/print?articleId=184402190&siteSecti. Close any files specific to THIS object. Write any methods that are different from the superclass's method. Use the preprocessor #define to define the class. Close any files opened in constructor. Call the superclass's destructor. at_end Return TRUE if current member is last member. } Table 1 For any base class: 1. Call the superclass's constructor. } else { printf("Not Found (Strike a Key)\n"). For any subclass: 1. Write the constructor."Smith") == TRUE) { pe->replace_member(pe. b. pe->next(pe). a. etc. pe->top(pe). Use superclass's definition. Assign the new/different methods written in step 2. 3. printf("Total members = %ld\n". Table 2 METHOD PURPOSE ------------------------------------------------------------------------ at_top Return TRUE if current member is top member. Dobb's | Object-Oriented Programming In C | July 01. while( ! pe->at_end(pe) ) { pe->display(pe). Use free(). 2. is_empty Return TRUE if LIST is empty. Allocate memory for this object. 3. This includes the allocation of additional memory. a. b.pe->tell(pe)). Free only memory specific to THIS object. b. c. Allocate memory for the object. Assign methods by setting function pointers to the methods written in step 3. 4. 4. 1990 http://www. 2. d. then add new methods and attributes. } pe->end(pe). pe->top(pe).pe->total_members(pe)). a. FALSE otherwise.. Write the constructor. the opening of files. etc. This includes the allocation of additional memory. c. Write the destructor. a. e. Write the destructor. getch().Dr. the opening of files. A method must take a pointer to the object calling it as the first parameter. 5.. Initialize attributes. Use the class and typedef to define an object. if (pe->find(pe.&jane). Initialize attributes. Free any additional memory allocated by constructor. f. b. 11 of 12 2/15/2017 4:31 PM . Free the memory used by the superclass. } printf("\nRedisplaying phone list:\n"). not the destructor. c. Free this object.

do nothing. seek Search to a position in the list. find Search the list for an implementation defined member. do nothing. Terms of Service | Privacy Statement | Copyright © 2017 UBM Tech. top Make the top member current.Dr. tell Return the position. Use like fseek. current Return a pointer to the current member. next Make the member after this one current... If current member is top. All rights reserved. 1990 http://www.drdobbs. replace_member Replace data in current member. Dobb's | Object-Oriented Programming In C | July 01. display Display the current member. The top member is 0. 12 of 12 2/15/2017 4:31 PM . If not found don't change currency. If current member is last. end Make the last member current. prev Make the member previous to this one current. total_members Return the total number of members int the list.com/article/print?articleId=184402190&siteSecti. from the start of the list of the current member. add_member Add a new member to the list.