Presentation is loading. Please wait.

Presentation is loading. Please wait.

Introduction to the Object-oriented Data Protocol © Dr. David Workman COP4331 School of EE and CS February 4, 2010.

Similar presentations


Presentation on theme: "Introduction to the Object-oriented Data Protocol © Dr. David Workman COP4331 School of EE and CS February 4, 2010."— Presentation transcript:

1 Introduction to the Object-oriented Data Protocol © Dr. David Workman COP4331 School of EE and CS February 4, 2010

2 Spring 2010COP43312 Principle #1 The ASCII image of a class instance on an external storage medium should be of the same general form as the class declaration in the implementation language omitting all details except those defining critical data members. Values of primitive data members are represented by their declared name follow by a colon (:) followed by a valid literal of their declared type. For data members that are class instances of program-defined types, this principle should be applied recursively. Data members that are instances of language-defined classes should appear in the external image only if the language specifies an ASCII format for instances of such classes. If such a specification does not exist, these data members shall be initialized using the default constructor from the relevant class(es). The ASCII image of data members that are pointer types should be a valid ASCII image of the reference type preceded by an asterisk (*). The ASCII image of data members that are arrays shall have the format indicated below: Array{ size: … }Array where n is the number of array elements and is the ASCII image of an instance of the array element type or class; token delimiters shall be one or more whitespace characters.

3 Spring 2010COP43313 Example: Grocery class Grocery { private: //data members string name; double markup; int cost; //in cents public: //methods Grocery(); //default constructor Grocery( string Name, double Markup, int Cost);//parametric constructor virtual ~Grocery(); // virtual destructor int getCost() const { return cost }; // in-line inspector int getPrice() const; // property (computed) string getName() const { return name; };//in-line inspector }; Grocery{ name: hamburger markup: 1.75 cost: 129 }Grocery Input (output) stream Advantages of OO Data: 1.The source code for the class declaration is a specification of the external ASCII format. 2.All program-defined classes are treated uniformly. 3.External ASCII images are self-descriptive and easily read and understood. 4.Matching opening and closing tokens clear mark the beginning and the end of the data image, even if they are far apart in the input stream. 5.Images in this format can be easily nested to any depth. 6.This style is XML compatible. Boundary methods could be easily adapted to produce any XML format.

4 Spring 2010COP43314 Example: Grocery Grocery{ name: hamburger markup: 1.75 cost: 129 }Grocery Input (output) stream Ifstream fin; fin.open("input.txt"); ostream fout; fout.open("output.txt"); Grocery item; Item.Extract( fin ); // parses input stream to initialize item Item.Insert( fout ); // inserts the ASCII image as it appears on input Client Code: class Grocery { private: //data members string name; double markup; int cost; //in cents public: //methods Grocery(); //default constructor Grocery( string Name, double Markup, int Cost);//parametric constructor virtual ~Grocery(); // virtual destructor int getCost() const { return cost }; // in-line inspector int getPrice() const; // property (computed) string getName() const { return name; };//in-line inspector void Extract( ifstream& fin ) throw(TokenError); //Extractor void Insert( ostream& fout ); //Insertor }; Boundary methods

5 Spring 2010COP43315 Example: Grocery Grocery{ name: hamburger markup: 1.75 cost: 129 }Grocery Input (output) stream Ifstream fin; fin.open("input.txt"); ostream fout; fout.open("output.txt"); Grocery item; fin >> item; // parses input stream to initialize item fout << item; // inserts the ASCII image as it appears on input Client Code: class Grocery { private: //data members string name; double markup; int cost; //in cents public: //methods Grocery(); //default constructor Grocery( string Name, double Markup, int Cost);//parametric constructor virtual ~Grocery(); // virtual destructor int getCost() const { return cost }; // in-line inspector int getPrice() const; // property (computed) string getName() const { return name; };//in-line inspector void Extract( ifstream& fin ) throw(TokenError); //Extractor void Insert( ostream& fout ); //Insertor friend ifstream& operator>>( ifstream& fin, Grocery& obj) throw(TokenError); friend ostream& operator<<( ostream& fout, Grocery& obj); }; Boundary operators

6 Spring 2010COP43316 Implementation: part A //data members // string name; // double markup; // int cost; //in cents //constructors Grocery:: Grocery() { //default constructor } Grocery::Grocery( string Name, double Markup, int Cost): name(Name), markup(Markup), cost(Cost) { //parametric constructor } //destructor Grocery::~Grocery() { // virtual destructor } //Properties int Grocery::getPrice() const { //Property return (int)(cost*markup + 0.5); } Grocery.cpp

7 Spring 2010COP43317 Implementation: part B //data members // string name; // double markup; // int cost; //in cents //Boundary methods void Grocery::Extract( ifstream& fin ) throw(TokenError) { //Extractor (boundary method) // Exact details provided later string token; fin >> token; if( token != "Grocery{" ) throw TokenError("Missing open token!", " Grocery::Extract()"); //… } void Grocery::Insert( ostream& fout ) { //Insertor (boundary method) fout << " Grocery{ " << "name: " << name << " markup: " << markup << " cost: " << cost << " }Grocery "; } //Friends ifstream& operator>>( ifstream& fin, Grocery& Obj) throw(TokenError) { obj.Extract( fin ); return fin; } ostream& operator<<( ostream& fout, Grocery& Obj) { obj.Insert(fout); return fout; } Grocery.cpp

8 Spring 2010COP43318 Class Hierarchies Grocery{ name: hamburger markup: 1.75 cost: $1.29 }Grocery Produce{ name: apples markup: 2.25 cost: $0.29 weight: 2.5 }Produce Grocery Produce Money class Grocery { private: //data members string name; double markup; Money cost; // $dddd.dd public: //methods Grocery(); //default constructor Grocery( string Name, double Markup, int Cost);//parametric constructor virtual ~Grocery(); // virtual destructor int getCost() const { return cost }; // in-line inspector int getPrice() const; // property (computed) string getName() const { return name; };//in-line inspector void Extract( ifstream& fin ) throw(TokenError); //Extractor void Insert( ostream& fout ); //Insertor friend ifstream& operator>> ( ifstream& fin, Grocery& obj) throw (TokenError); friend ostream& operator<< ( ostream& fout, Grocery& obj); }; How do we Implement Class Produce?

9 Spring 2010COP43319 Class Hierarchies Grocery{ name: hamburger markup: 1.75 cost: $1.29 }Grocery Produce{ name: apples markup: 2.25 cost: $0.29 weight: 2.5 }Produce Grocery Produce Money class Produce: public Grocery { private: // data members of Grocery are inherited, so define only new members double weight; public: //methods Produce(); //default constructor Produce( string Name, double Markup, Money Cost, double weight);//parametric constructor virtual ~Produce(); //virtual destructor //Inspector methods for Grocery are inherited double getWeight(); //Produce specific inspector void Extract( ifstream& fin ) throw(TokenError); //Extractor void Insert( ostream& fout ); //Insertor friend ifstream& operator>> ( ifstream& fin, Produce& obj) throw (TokenError); friend ostream& operator<< ( ostream& fout, Produce& obj); }; Must override! friends are not methods, so they cannot be inherited. So, must define them again in subclass. (There is a better way to do this by exploiting dynamic binding – a solution we will discuss later)

10 Spring 2010COP433110 Class Produce: Implementation Problems: –Extract must parse the inherited data members. However, to do this correctly violates principles of good OO design. (a) Information about inherited data members (private in the superclass) must be encoded in the subclass – thus, breaking the principle of information hiding. (b) The superclass must be modified to provide setter methods to give the subclass access to inherited data members – while these setter methods can be made "protected" to limit access only to subclasses, this is a practice to be avoided if at all possible. It cries out for a better solution. –The solution implied above becomes even worse if any changes are made to data members of a superclass – all subclasses have to be modified to be consistent with those changes. A maintenance nightmare!

11 Spring 2010COP433111 A Better Solution Design Principle 2: For each type of external input source or medium, a class should provide one or more overloaded methods that parse a class instance on that medium. Similarly, for each external output sink or medium, a class should provide one or more overloaded methods that write a class instance to that medium. If the input medium and output medium are the same, then the image produced on that medium by an output method should be parsable by the input methods for that medium. Finally, the same naming convention should be used to define IO methods that perform the same function on the same external medium in different classes (principle of Polymorphism). All such IO methods should be declared virtual (in C++) and should designed to exploit runtime binding whenever possible.

12 Spring 2010COP433112 A Better Solution (contd) class Grocery { private: //data members string name; double markup; Money cost; // $dddd.dd public: //methods Grocery(); //default constructor Grocery( string Name, double Markup, int Cost);//parametric constructor Grocery( ifstream& fin ) throw (TokenError); // parametric constructor from input stream virtual ~Grocery(); // virtual destructor int getCost() const { return cost }; // in-line inspector int getPrice() const; // property (computed) string getName() const { return name; };//in-line inspector virtual void Extract( ifstream& fin ) throw (TokenError); //Extractor virtual void Insert( ostream& fout ); //Insertor friend ifstream& operator>> ( ifstream& fin, Grocery& obj) throw (TokenError); friend ostream& operator<< ( ostream& fout, Grocery& obj); protected: virtual void Get( ifstream& fin ) throw (TokenError); //Extractor virtual void Put( ostream& fout ); }; Base Class Virtual protected methods designed to parse data members.

13 Spring 2010COP433113 Solution: Base Class void BaseClass::Extract(… ) … { //1. Read and check open token for this class; throw TokenError if erroneous //2. Call Get(…) to parse data members for this class; //3. Read and check closing token for this class; throw TokenError if erroneous } Void BaseClass::Get(… ) … { // for each data member to be read: // read and check member label; throw TokenError if match not found // parse value of data member with appropriate extraction operator } Ifstream& operator>> ( ifstream& fin, Baseclass& Obj ) throw (TokenError) { Obj.Extract( fin ); // Runtime binding applies – Extract() of dynamic type is called. return fin; } Analogous algorithm used for Insert() and Put(), except no error checking is needed and no exceptions need be thrown. ostream& operator<< ( ostream& fout, Baseclass& Obj ) { Obj.Insert( fout ); // Runtime binding applies – Insert() of dynamic type is called. return fout; } Friends defined ONLY in Base Class! void BaseClass::BaseClass ( ifstream& fin ) throw (TokenError) { // parametric constructor parses image on input stream Extract( fin ); }

14 Spring 2010COP433114 Solution: Any Subclass class Produce: public Grocery { private: // data members of Grocery are inherited, so define only new members double weight; public: //methods Produce(); //default constructor Produce( string Name, double Markup, Money Cost, double weight);//parametric constructor Produce( ifstream& fin) throw (TokenError); //parametric constructor extracts from input stream virtual ~Produce(); //virtual destructor //Inspector methods for Grocery are inherited double getWeight(); //Produce specific inspector virtual void Extract( ifstream& fin ) throw(TokenError); //Extractor virtual void Insert( ostream& fout ); //Insertor protected: virtual void Get( ifstream& fin ) throw (TokenError); //Extractor virtual void Put( ostream& fout ); //Inserter }; Any subClass Virtual protected methods designed to parse data members.

15 Spring 2010COP433115 Solution: Any Subclass void SubClass::Extract(… ) … { //1. Read and check open token for this class; throw TokenError if erroneous //2. Call Get(…) to parse data members for this class; //3. Read and check closing token for this class; throw TokenError if erroneous } void SubClass::Get(… ) … { Parent::Get( fin ); // call the Get() method of immediate parent class to parse all inherited data members. // for each data member defined explicitly in this subclass: // read and check member label; throw TokenError if match not found // parse value of data member with appropriate extraction operator } Analogous algorithm used for Insert() and Put(), except no error checking is needed and no exceptions need be thrown. void SubClass::SubClass ( ifstream& fin ) throw (TokenError) { // parametric constructor parses image on input stream Extract( fin ); } void SubClass::SubClass ( s1,s2,,,sn, D1,D2,…Dm) : ParentClass(s1,s2,…sn),d1(D1),…dm(Dm) { // parametric constructor specifies data members explicitly … } Calls parametric constructor of Immediate parent class. Initialization list

16 Spring 2010COP433116 Client Code: Style1 Style 1: The number and sequence of type instances is known and fixed at design time. //Assume fin and fout are input and output streams, respectively. int main() { ofstream fout; fout.open("grocery.out"); ifstream fin; fin.open("grocery.in"); Grocery g1( fin ), //Constructs g1 from input stream g2, //Default constructor is called g3(“G3”, 1.25, 25); //Explicit constructor is called Produce p1( fin ), //Constructs p1 from input file p2, p3(“P3”, 2.0, 150, 4.5); g2.Extract( fin ); //parses g2 from file fin >> p2; //parses p2 from file g3.Insert( fout ); g2.Insert( fout ); g1.Insert( fout ); p3.Insert( fout ); p2.Insert( fout ); p1.Insert( fout ); fin.close(); fout.close(); return 0; }//main Grocery{ name: G1 markup: 3.25 cost: $5.00 }Grocery Produce{ name: P1 markup: 2.50 cost: $3.00 weight: 1.75 }Produce Grocery{ name: G2 markup: 2.25 cost: $4.00 }Grocery Produce{ name: P2 markup: 1.50 cost: $2.00 weight: 6.0 }Produce Input Stream Grocery{ name: G3 markup: 1.25 cost: $0.25 }Grocery Grocery{ name: G2 markup: 2.25 cost: $4.00 }Grocery Grocery{ name: G1 markup: 3.25 cost: $5.00 }Grocery Produce{ name: P3 markup: 2.0 cost: $1.50 weight: 4.5 }Produce Produce{ name: P2 markup: 1.5 cost: $2.00 weight: 6 }Produce Produce{ name: P1 markup: 2.5 cost: $3.00 weight: 1.75 }Produce Output Stream

17 Spring 2010COP433117 Client Code: Style2 Style 2: The number and sequence of type instances is unknown and can vary at runtime. //Assume fin and fout are input and output streams, respectively. int main() { ifstream fin; fin.open("grocery.in"); long inputpos; //variable needed to record file access point string token //variable needed to receive next input token inputpos = fin.tellg(); //record input file position (before first instance) while( fin >> token ) //read next open token if the file stream is not empty { fin.seekg( inputpos ); //restore file position to re-read last token if( token == “Grocery{” ) //test token value { Grocery g; g.Extract( fin ); //parse image of Grocery instance … //process Grocery instance }//if if( token == “Produce{” ) //test token value { Produce p; fin >> p; //parse image of Produce instance … //process Produce instance }//if inputpos = fin.tellg(); //record new file position (after last instance) }//while fin.close(); return 0; }//main NOTE: could have written Grocery g( fin ); NOTE: could have written Produce p( fin );


Download ppt "Introduction to the Object-oriented Data Protocol © Dr. David Workman COP4331 School of EE and CS February 4, 2010."

Similar presentations


Ads by Google