1 / 30

Structured Data

Structured Data. A major problem with modular code is the need to use a large number of parameters to deal with several objects that might be closely related to each other.

mackeyjulia
Télécharger la présentation

Structured Data

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Structured Data A major problem with modular code is the need to use a large number of parameters to deal with several objects that might be closely related to each other. A preferable approach would be to group these values together in a single structure, which could easily be passed to a function as a single parameter. void processSale (string inventoryNbr, float price, float weight, int &nbrInStock, int &nbrSoldThisYear, int storeNbr, int month, int day, int year, float time); void processSale (Merchandise &itemSold, Time timeOfSale); CS 150

  2. The C++ struct C++ provides a struct mechanism for defining such structures. struct Merchandise { string inventoryNbr; float price; float weight; int nbrInStock; int nbrSoldThisYear; int storeNbr; }; struct Time { int month; int day; int year; float timeOfDay; }; CS 150

  3. Structure Variables and Parameters Once a struct has been defined, variables of that type can be declared. const float EmployeeDiscountPercent; int dailyQuota; Merchandise saleItem, itemSold; Time timeOfSale, openingTime, closingTime; And parameters and functions of that type can be used. void processSale (Merchandise &itemSold, Time timeOfSale); Time calculateStoreClosing(int monthNo, int dayNo, int yearNo);  void main() {  closingTime = calculateStoreClosing(12, 24, 1998); processSale(saleItem, closingTime);  } CS 150

  4. Working with the Structure Members The data elements comprising a struct are known as its members. The members are accessed by means of the C++ “dot” notation. Time calculateStoreClosing(int monthNo, int dayNo, int yearNo) { Time t; t.month = monthNo; t.day = dayNo; t.year = yearNo; if ((monthNo == 12) && (dayNo == 24)) t.timeOfDay = 18.00F; else t.timeOfDay = 22.00F; return t; } void processSale (Merchandise &itemSold, Time timeOfSale); { if (timeOfSale.timeOfDay < 8.00) itemSold.price -= EmployeeDiscountPercent*itemSold.price; itemSold.nbrInStock--; itemSold.nbrSoldThisYear++; } CS 150

  5. A Complete Example /////////////////////////////////////////////////// // priceTag.cpp // // This program generates the text for a store's // // price tags, using a predefined output format. // /////////////////////////////////////////////////// #include <iostream> #include <iomanip> #include <stdlib> #include <string>using namespace std; const int TAG_HEIGHT = 7; const int TAG_WIDTH = 20; const int INV_NBR_SIZE = 10; const int PRICE_TEXT_SIZE = 5; const char BORDER_CHAR = '*'; struct PriceTag { string inventoryNumber; float price; int storeNumber; }; // Notice the REQUIRED semicolon! int startSession(); char askUserForMore(); int howManyQuery(); PriceTag getTagInfo(int store); void outputTag(PriceTag tag); The PriceTag structure contains a character array, an integer, and a floating-point number. The closing brace after a structure definition must be followed by a semicolon! A function with type PriceTag. A PriceTag parameter, passed by value. CS 150

  6. The PriceTag Example (Continued) //////////////////////////////////////////////////// // The main function repeatedly asks the user for // // info regarding desired price tags, and then // // generates the text for the desired price tags. // //////////////////////////////////////////////////// void main() { PriceTag pTag; int quantity; int i; int storeNo = startSession(); char YorN = askUserForMore(); while (YorN =='Y') { quantity = howManyQuery(); pTag = getTagInfo(storeNo); for (i = 1; i <= quantity; i++) outputTag(pTag); YorN = askUserForMore(); } return; } Declaring a PriceTag variable. Assigning a PriceTag a value by means of an assignment statement. Sending the PriceTag as a function argument. CS 150

  7. The PriceTag Example (Continued) // The startSession function outputs a brief header and // // requests the user's store number, which is returned. // int startSession() { int ZMartNo; cout << "OFFICIAL Z-MART PRICE TAG GENERATOR" << endl; cout << "Enter your store number: "; cin >> ZMartNo; return ZMartNo; } // The askUserForMore function queries the user whether to generate // // more price tags; an upper-case 'Y' or 'N' is returned. // char askUserForMore() { static string insertWord = " some "; char response; cout << endl; cout << "Do you wish to generate" << insertWord << "price tags? (Enter Y or N): "; cin >> response; response = toupper(response); while ((response != 'Y') && (response != 'N')) { cout << "Inappropriate response. Try again." << endl; cout << "Do you wish to generate" << insertWord << "price tags? (Enter Y or N): "; cin >> response; response = toupper(response); } insertWord = " MORE "; return response; } CS 150

  8. The PriceTag Example (Continued) // The howManyQuery function queries the user about how many tags to output. // int howManyQuery() { int qty; cout << "How many tags would you like to produce? "; cin >> qty; while (qty <= 0) { cout << qty << "??? You must enter a POSITIVE number: "; cin >> qty; } return qty; } // The getTagInfo function queries the user about the inventory number and price of // // the item for which tags are being produced, and generates the PriceTag object. // PriceTag getTagInfo(int store) { PriceTag pt; string stockNumber; pt.storeNumber = store; cout << "What is the inventory number of the item? "; cin >> stockNumber; while (stockNumber.length() > INV_NBR_SIZE-1) { cout << "You must be mistaken. That's much too long." << endl; cout << "What is the inventory number of the item? "; cin >> stockNumber; } pt.inventoryNumber = stockNumber; cout << "What is the price of the item? "; cin >> pt.price; return pt; } Assigning a member a value. Using a member as a parameter. Outputting a member value. CS 150

  9. The PriceTag Example (Continued) // The outputTag function outputs the information in the parameterized PriceTag, // // formatted so the inventory number and the price are centered, the store number is // // in the bottom right corner, and the border is filled with the proper character. // void outputTag(PriceTag tag) { int columnNumber; int i; for (i = 1; i <= TAG_WIDTH; i++) cout << BORDER_CHAR; cout << endl; columnNumber = (TAG_WIDTH)/2 + tag.inventoryNumber.length/2; cout << BORDER_CHAR << setw(columnNumber-1) << tag.inventoryNumber << setw(TAG_WIDTH-columnNumber) << BORDER_CHAR << endl << BORDER_CHAR << setw(TAG_WIDTH-1) << BORDER_CHAR << endl; columnNumber = (TAG_WIDTH)/2 + PRICE_TEXT_SIZE/2; cout.setf(ios::fixed); cout << BORDER_CHAR << setw(columnNumber-PRICE_TEXT_SIZE-1) << '$' << setprecision(2) << setw(PRICE_TEXT_SIZE) << tag.price << setw(TAG_WIDTH-columnNumber) << BORDER_CHAR << endl; for (i = 1; i <= TAG_HEIGHT-7; i++) cout << BORDER_CHAR << setw(TAG_WIDTH-1) << BORDER_CHAR << endl; cout << BORDER_CHAR << setw(TAG_WIDTH-3) << tag.storeNumber << setw(2) << BORDER_CHAR << endl; for (i = 1; i <= TAG_WIDTH; i++) cout << BORDER_CHAR; cout << endl; } Outputting the three members CS 150

  10. The PriceTag Example (Continued) CS 150

  11. C++ Classes To enhance modularity and information hiding even further, it would be nice if we could create types for which the internal workings are “private” to the rest of our program, and which can only be accessed or altered by means of specified “public” functions. BankAccount acct; cout >> “Enter interest rate: ”; cin << acct.intRate; BankAccount acct; float rate; cout >> “Enter interest rate: ”; cin << rate; acct.setIntRate(rate);  void BankAccount::setIntRate(float r) { if ((r<=0.0F) || (r>=0.1F)) intRate = 0.01F else intRate = r; return; } Doesn’t prevent rates below 0% or above 10%! Does prevent rates below 0% or above 10%! CS 150

  12. The C++ class C++ provides a class mechanism for defining such types. class BankAccount { public: void setIntRate(float newIntRate); void setBalance(float newBalance); bool checkAcctNbr(string testAcctNbr); bool checkATMCode(string testATMCode); float getIntRate(); float getBalance(); private: void setAcctNbr(string newAcctNbr); void setATMCode(string newATMCode); string getAcctNbr(); string getATMCode(); float intRate; float balance; string acctNbr; string atmCode; }; Prototypes for “public member functions”, which can be used by any function that declares a variable of this type. Prototypes for “private member functions”, which can only be used by the other member functions of this type. “Private data members”, which can only be used by the member functions of this type. CS 150

  13. The Scope Resolution Operator When implementing the member functions, the compiler needs to know that they are members of the class, and are only defined within the context of the object that’s using them. The scope resolution operator, ::, is used to accomplish this. void BankAccount::setIntRate(float newIntRate) { if ((newIntRate < 0.0F) || (newIntRate > 0.1F)) intRate = 0.01F; else intRate = newIntRate; } bool BankAccount::checkATMCode(string testATMCode) { return (atmCode == testATMCode); } string BankAccount::getATMCode() { return atmCode; } CS 150

  14. Working with the Class Members Just like with structures, the dot operator is used to access class members, both data members and member functions. void validateAcctNbr(BankAccount acct, string nbr) { if (accountNumber == nbr) cout << “Account Number Validated”; else cout << “Account Number Invalid! Call the cops!”; } Compilation Error! accountNumber is not a variable in this function! Compilation Error! accountNumber is a private data member of the BankAccount class! void validateAcctNbr(BankAccount acct, string nbr) { if (acct.accountNumber == nbr) cout << “Account Number Validated”; else cout << “Account Number Invalid! Call the cops!”; } void validateAcctNbr(BankAccount acct, string nbr) { if (acct.getAcctNbr() == nbr) cout << “Account Number Validated”; else cout << “Account Number Invalid! Call the cops!”; } Compilation Error! getAcctNbr is a private member function of the BankAccount class! void validateAcctNbr(BankAccount acct, string nbr) { if (acct.checkAcctNbr(nbr)) cout << “Account Number Validated”; else cout << “Account Number Invalid! Call the cops!”; } No problemo! checkAcctNbr is a public member function of the BankAccount class! CS 150

  15. A Complete Example // circleDrawingDriver.cpp // // This program generates circle data and draws them using ASCII characters. // #include <iostream> #include <iomanip> #include <cmath>using namespace std; const float PI = 3.1416F; const int PADDING = 3; const int ASCII_ZERO_VALUE = 48; class Circle { public: Circle(); // Constructor void setCoordinates(int x, int y); // Member functions void setRadius(int r); void setASCIICharacter(char ch); float computeArea(); float computePerimeter(); void displayCircleAttributes(); void drawCircle(); int getXCoord() const; // Accessor functions int getYCoord() const; int getRadius() const; char getASCIICharacter() const; private: int xCoord; // Data members int yCoord; int radius; char asciiCharacter; }; // Notice the REQUIRED semicolon! “Constructors” create new objects of this class; with no parameters, this one’s known as the “default” constructor, and is called whenever a variable of type Circle is declared. The declaration of the Circle class. Regular public member functions; they can be called by any function with a Circle variable. Accessor public member functions; they can access but not alter a Circle object. Private data members; they can only be used by Circle member functions. CS 150

  16. The Circle Example (Continued) ////////////////////////////////////////////////////////////////// // The main function serves as a driver to display a variety of // // circles with a variety of sizes, positions, and characters. // ////////////////////////////////////////////////////////////////// void main() { Circle circ; char YorN; int count = 1; int positionX = 4; int positionY = 2; cout << "Ready for the first circle? (Enter Y or N) "; cin >> YorN; while ((YorN == 'y') || (YorN == 'Y')) { circ.setASCIICharacter(char(ASCII_ZERO_VALUE+count)); circ.setRadius(count+3); circ.setCoordinates(positionX,positionY); circ.displayCircleAttributes(); circ.drawCircle(); cout << "Ready for another circle? (Enter Y or N) "; cin >> YorN; count++; positionX = (positionX + 11) % 13; positionY = (positionY + 13) % 11; } return; } The declaration of a variable of type Circle. Calling some of Circle’s public member functions; note the use of the dot notation. CS 150

  17. The Circle Example (Continued) // This default constructor sets up the data members with default values. // Circle::Circle() { xCoord = yCoord = radius = 0; asciiCharacter = ' '; } // Assign the x- and y- coords of the circle's center with parameterized values. // void Circle::setCoordinates(int x, int y) { xCoord = x; yCoord = y; return; } // Assign the radius of the circle the parameterized value. // void Circle::setRadius(int r) { radius = r; return; } // Assign the fill character of the circle the parameterized value. // void Circle::setASCIICharacter(char ch) { asciiCharacter = ch; return; } The Circle’s default constructor initializes the data members; default constructors do not have to do initialization. Notice that the dot operator is not needed to access members in member functions themselves; the compiler recognizes that the Circle being operated upon is the one being referred to. CS 150

  18. The Circle Example (Continued) // Compute and return the area of the circle. // float Circle::computeArea() { return PI * radius * radius; } // Compute and return the perimeter of the circle. // float Circle::computePerimeter() { return 2 * PI * radius; } // Output the circle's data member values, as // // well as the area and perimeter of the Circle. // void Circle::displayCircleAttributes() { cout.setf(ios::fixed); cout << setprecision(4); cout << "Center's x-coordinate: " << xCoord << endl; cout << "Center's y-coordinate: " << yCoord << endl; cout << "Circle's radius: " << radius << endl; cout << "Circle's area: " << computeArea() << endl; cout << "Circle's perimeter: " << computePerimeter() << endl; cout << "Circle's fill character: " << asciiCharacter << endl; } Also notice that the dot operator is not needed to access member functions in member functions themselves; the compiler still recognizes that the Circle being operated upon is the one being referred to. CS 150

  19. The Circle Example (Continued) // Output the Circle, using its ASCII character to draw it, // // as well as vertical and horizontal symbols to draw the // // coordinate axes, and an 'X' at the center of the circle. // void Circle::drawCircle() { const int PADDING = 4; const float HEIGHT_WIDTH_RATIO = 1.5F; int lowerX = (xCoord-radius < -PADDING) ? (xCoord-radius-PADDING) : -PADDING; int upperX = (xCoord+radius > PADDING) ? (xCoord+radius+PADDING) : PADDING; int lowerY = (yCoord-radius < -PADDING) ? (yCoord-radius-PADDING) : -PADDING; int upperY = (yCoord+radius > PADDING) ? (yCoord+radius+PADDING) : PADDING; for (int y = upperY; y >= lowerY; y--) { for (int x = int(HEIGHT_WIDTH_RATIO*lowerX); x <= int(HEIGHT_WIDTH_RATIO*upperX); x++) { if ((x == xCoord) && (y == yCoord)) cout << 'X'; else if (pow((x-xCoord)/HEIGHT_WIDTH_RATIO,2) + pow(y-yCoord,2) <= pow(radius,2)) cout << asciiCharacter; else if ((x == 0) && (y == 0)) cout << '+'; else if (x == 0) cout << '|'; else if (y == 0) cout << '-'; else cout << ' '; } cout << endl; } } CS 150

  20. The Circle Example (Continued) // Access and return the Circle's x-coordinate value. // int Circle::getXCoord() const { return xCoord; } // Access and return the Circle's y-coordinate value. // int Circle::getYCoord() const { return yCoord; } // Access and return the value of the Circle's radius. // int Circle::getRadius() const { return radius; } // Access and return the value of the Circle's ASCII fill character. // char Circle::getASCIICharacter() const { return asciiCharacter; } The accessor functions have been set up as constant member functions; this guarantees that calling them will not alter the values of any of the Circle’s data members.. CS 150

  21. The Circle Example (Continued) CS 150

  22. Class Definition and Implementation Files ///////////////////////////////////////////////////////// // circle.h The class definition for the Circle class // ///////////////////////////////////////////////////////// #ifndef CIRCLE_H#include<iostream>using namespace std; class Circle { public: Circle(); // Constructor void setCoordinates(int x, int y); // Member functions void setRadius(int r); void setASCIICharacter(char ch); float computeArea(); float computePerimeter(); void displayCircleAttributes(); void drawCircle(); int getXCoord() const; // Accessor functions int getYCoord() const; int getRadius() const; char getASCIICharacter() const; private: int xCoord; // Data members int yCoord; int radius; char asciiCharacter; }; // Notice the REQUIRED semicolon! #define CIRCLE_H #endif To relieve the programmer from the burden of rebuilding the code associated with a completed class, and to make the class reusable with other driver programs, the class definition is normally placed in a header file and the class implementation is normally placed in a separate program file. The Circle’s class definition file: circle.h CS 150

  23. The Class Implementation File: circle.cpp // Access and return the Circle's x-coordinate value. // int Circle::getXCoord() const { return xCoord; } // Access and return the Circle's y-coordinate value. // int Circle::getYCoord() const { return yCoord; } // Access and return the value of the Circle's radius. // int Circle::getRadius() const { return radius; } // Access and return the value of the Circle's ASCII fill character. // char Circle::getASCIICharacter() const { return asciiCharacter; } // Output the Circle, using its ASCII character to draw it, // // as well as vertical and horizontal symbols to draw the // // coordinate axes, and an 'X' at the center of the circle. // void Circle::drawCircle() { const int PADDING = 4; const float HEIGHT_WIDTH_RATIO = 1.5F; int lowerX = (xCoord-radius < -PADDING) ? (xCoord-radius-PADDING) : -PADDING; int upperX = (xCoord+radius > PADDING) ? (xCoord+radius+PADDING) : PADDING; int lowerY = (yCoord-radius < -PADDING) ? (yCoord-radius-PADDING) : -PADDING; int upperY = (yCoord+radius > PADDING) ? (yCoord+radius+PADDING) : PADDING; for (int y = upperY; y >= lowerY; y--) { for (int x = int(HEIGHT_WIDTH_RATIO*lowerX); x <= int(HEIGHT_WIDTH_RATIO*upperX); x++) { if ((x == xCoord) && (y == yCoord)) cout << 'X'; else if (pow((x-xCoord)/HEIGHT_WIDTH_RATIO,2) + pow(y-yCoord,2) <= pow(radius,2)) cout << asciiCharacter; else if ((x == 0) && (y == 0)) cout << '+'; else if (x == 0) cout << '|'; else if (y == 0) cout << '-'; else cout << ' '; } cout << endl; } } // Assign the fill character of the circle the parameterized value. // void Circle::setASCIICharacter(char ch) { asciiCharacter = ch; return; } // Compute and return the area of the circle. // float Circle::computeArea() { return PI * radius * radius; } // Compute and return the perimeter of the circle. // float Circle::computePerimeter() { return 2 * PI * radius; } // Output the circle's data member values, as // // well as the area and perimeter of the Circle. // void Circle::displayCircleAttributes() { cout.setf(ios::fixed); cout << setprecision(4); cout << "Center's x-coordinate: " << xCoord << endl; cout << "Center's y-coordinate: " << yCoord << endl; cout << "Circle's radius: " << radius << endl; cout << "Circle's area: " << computeArea() << endl; cout << "Circle's perimeter: " << computePerimeter() << endl; cout << "Circle's fill character: " << asciiCharacter << endl; } ///////////////////////////////////////////////////////////////// // circle.cpp The class implementation for the Circle class. // ///////////////////////////////////////////////////////////////// #include <iostream> #include <iomanip> #include <cmath> #include "circle.h“using namespace std; const float PI = 3.1416F; const int PADDING = 3; // This default constructor sets up the data members with default values. // Circle::Circle() { xCoord = yCoord = radius = 0; asciiCharacter = ' '; } // Assign the x- and y- coordinates of the circle's center with parameterized values. // void Circle::setCoordinates(int x, int y) { xCoord = x; yCoord = y; return; } // Assign the radius of the circle the parameterized value. // void Circle::setRadius(int r) { radius = r; return; } CS 150

  24. The Driver File: circleDrawingDriver2.cpp // circleDrawingDriver2.cpp // // This program generates the data for circles and then draws them using ASCII characters. // #include <iostream> #include "circle.h"using namespace std; const int ASCII_ZERO_VALUE = 48; // The main function displays a variety of circles. // void main() { Circle circ; char YorN; int count = 1; int positionX = 4; int positionY = 2; cout << "Ready for the first circle? (Enter Y or N) "; cin >> YorN; while ((YorN == 'y') || (YorN == 'Y')) { circ.setASCIICharacter(char(ASCII_ZERO_VALUE+count)); circ.setRadius(count+3); circ.setCoordinates(positionX,positionY); circ.displayCircleAttributes(); circ.drawCircle(); cout << "Ready for another circle? (Enter Y or N) "; cin >> YorN; count++; positionX = (positionX + 11) % 13; positionY = (positionY + 13) % 11; } return; } CS 150

  25. An Alternative Driver //////////////////////////////////////////////////// // diagonalDotDriver.cpp // // This program generates same-sized circles that // // are displayed at a diagonal to each other. // //////////////////////////////////////////////////// #include <iostream> #include "circle.h"using namespace std; //////////////////////////////////////////////////////// // The main function drives the diagonal dot display. // //////////////////////////////////////////////////////// void main() { Circle circ; circ.setASCIICharacter('O'); circ.setRadius(4); for (int i = 0; i < 40; i += 8) { circ.setCoordinates(i,0); circ.drawCircle(); } return; } Note that this driver requires no changes to the definition of the Circle class! CS 150

  26. Constructors There are three basic types of constructors in C++ programming. Circle::Circle() { xCoord = yCoord = radius = 0; asciiCharacter = ' '; } Default Constructor Called when a new variable of this type is declared. (Only one allowed.) Circle::Circle() { } Circle::Circle(int x, int y, int r, char ch) { xCoord = x; yCoord = y; radius = r; asciiCharacter = ch; } Initializing Constructor Called when variable of this type is having some or all of its data member values initialized. (More than one allowed.) Circle::Circle(char ch) { asciiCharacter = ch; } Circle::Circle(const Circle &c) { xCoord = c.xCoord; yCoord = c.yCoord; radius = c.radius; asciiCharacter = c.asciiCharacter; } Copy Constructor Called when a variable of this type is passed by value to a function. (Only one allowed.) Note that constructors always have the same name as the class. CS 150

  27. Calling the Constructors Default Constructor Don’t call it with the empty parentheses; the compiler might conclude that this is a prototype! void main() { Circle roundo;  } void main() { Circle C1(3,-2,7,’$’); C2 = Circle(’!’);  } Initializing Constructor As long as the parameter lists differ in type, the compiler won’t get confused. void main() { Circle bigArc;  smileyFace(bigArc);  }  void smileyFace(Circle button) {  } Copy Constructor You might be able to pass by value without one, but the results would be unpredictable. CS 150

  28. Abstract Data Types To what extent does a programmer need to know the implementation of the Circle class in order to use it in a driver? Does the programmer need to know the types of the data members in order to use the constructors? Perhaps with that initializing constructor... Does the programmer need to know how the area and perimeter are being computed? Nope! Does the programmer need to know the types of the data members in order to set them or access them? Well, yeah... Does the programmer need to know anything about the data members in order to draw the circle or display its attributes? Not really... If the programmers who use a data type don’t have to know how its members are implemented, then it’s considered an abstract data type. CS 150

  29. Advantages of ADTs By limiting the required understanding of the class to the public members, modifiability, readability, and reusability are all enhanced! Object-Oriented Emphasis on what is being done Procedural Emphasis Upon How To Do Things CS 150

  30. Achieving ADT Status in C++ Private Members Only! (At least, private data members only!) Basic Public Broadcasting! (That is, use public member functions for only basic operations, and ensure that users know how to use them!) Show A Little Class! (Put your class definition and your class implementation in separate .h and .cpp files!) CS 150

More Related