CS 228 meeting -*- Outline -*- * structs in C++ (HR 5.1-2) ** syntax (5.1) recall that records are: linear, direct access, and heterogeneous emphasize heterogenity -------------------------- C++ structs IMPLEMENT RECORDS struct PhoneRecord { char name[50]; int number; }; struct BookType { char author[50]; char title[150]; int year; float price; }; enum GenderType {male, female, unknown}; struct EmployeeType { char firstInit; char lastInit; int age; GenderType gender; float hourlyWage; }; -------------------------- draw pictures of these ** client code -------------------------- DECLARING struct OBJECTS IN CLIENT CODE PhoneRecord bank, police, fire; BookType referenceManual; EmployeeType manager; EmployeeType worker1; EmployeeType dean = { 'E', 'H', 45, female, 75.0}; -------------------------- just like classes with default constructor, however, if the struct does have any constructors, then you can't use aggregate initialization as in the dean's record. -------------------------- USING struct OBJECTS IN CLIENT CODE // assignment to data members worker1.firstInit = 'G'; worker1.lastInit = 'L'; worker1.age = 38; worker1.gender = male; worker1.hourlyWage = 30.0; cout << worker1.age << endl; if (worker1.age > 65) { cout << worker1.firstInit << ". "; cout << worker1.lastInit << ". "; cout << "should retire"; } worker1.age = worker1.age + 1; const float MINIMUM = 4.65; void payMinimum(EmployeeType & emp) // MODIFIES: emp // POST: emp.hourlyWage >= MINIMUM { } -------------------------- write in: if (worker1.hourlyWage < MINIMUM) { worker1.hourlyWage = MINIMUM; } --------------------------- FOR YOU TO DO enum GenderType {male, female, unknown}; struct EmployeeType { char firstInit; char lastInit; int age; GenderType gender; float hourlyWage; }; IMPLEMENT THE FOLLOWING SPECIFICATIONS: void RaisePay(EmployeeType & emp, float rate) // PRE: 0.0 < rate && rate <= 1.0; // MODIFIES: emp // POST: emp.hourlyWage == // (1 + rate) * emp.hourlyWage void EqualizePay(EmployeeType & mgr, EmployeeType e) // MODIFIES: mgr // POST: make mgr's hourly wage // at least as high as e's pay. ---------------------------- *** semantics --------------------------------- MANIPULATING struct INSTANCES Can do: manager.age manager.age = 30; manager = worker1; // which means: manager.firstInit = worker1.firstInit; manager.lastInit = worker1.lastInit; manager.age = worker1.age; manager.gender = worker1.gender; manager.hourlyWage = worker1.hourlyWage; -------------------------------- the latter copies the data members of worker1 into manager (by memberwise assignment) --------------------------------- Cannot do: manager.age() manager == worker1 manager + worker1 --------------------------------- technically the same as a class, but with public the default Q: does this look familiar? -------------------------------- A struct IS A class WITH public DEFAULT struct PhoneRecord { char name[50]; int number; }; // same as struct PhoneRecord { public: char name[50]; int number; }; // same as class PhoneRecord { public: char name[50]; int number; }; -------------------------------- all the syntax and semantics of class applies to struct, the *only* technical difference is that public is the default visibility so when to use which? a question of programming rhetoric (making your code clear) -------------------------------- class VS. struct (USAGE) Use a class when: hiding information, have abstraction, have member functions used as ADT Use a struct when: no data is hidden, no abstraction, no member functions (except maybe constructors) used as impl. data structure -------------------------------- HR *never* use any function members Q: so if you want to make some data private, which should be used? ---------------------------------- PARAMETER PASSING struct PhoneRecord { char name[50]; int number; }; void assign2(PhoneRecord & v1, PhoneRecord & v2, PhoneRecord e1, PhoneRecord e2) { v1 = e1; v2 = e2; } -------------------------------- show how this works by drawing pictures note that the array is copied an aside: by wrapping an array in a struct, you can copy it, pass it by value, return it from function // PhoneRecordClient.C #include #include "PhoneRecord.h" #include "PhoneRecord-assign2.h" int main() { PhoneRecord mine = {"me", 5551122}; PhoneRecord yours = {"you", 5551234}; assign2(mine, yours, yours, mine); cout << "mine.name is " << mine.name << endl; cout << "yours.name is " << yours.name << endl; return 0; } -------------------------------- // InHouse.C #include "PhoneRecord.h" PhoneRecord InHouse( const PhoneRecord & pr) // PRE: pr.number >= 0; // POST: FCTVAL is just like pr // but retains only last 5 digits of // pr.number { } ---------------------------------- PhoneRecord result = pr; result.number %= 100000; return result; Show how the result is copied out, from the local variable result. Q: How would you use InHouse to print the local phone number of p? ---------------------------------- SCOPE OF MEMBER NAMES - member names are local to a struct ---------------------------------- just as is the case for classes ---------------------------------- struct BookType { char author[50]; char title[150]; int year; float price; }; struct DateType { int year; int month; int day; }; DateType independence; BookType refManual; int year; year = 1945; refManual.year = 1990; independence.year = 1776; ---------------------------------- It's okay to have all of these uses of year, because have to use name of instance then dot (.) first to get to struct ** combinations (p.209ff) --------------------------------- ALL NESTINGS OF TYPES ARE OK! - data members can be structs student.name.middleInit = 'T'; - data members can be arrays refManual.title[0] = '\0'; - arrays can contain structs employee[2].age = 30; - etc. students[4].name.first[0] = '\0'; --------------------------------- emphasize that you read this from the left, look at the type of each part so far... (you can even put class objects within a struct) *** simple example example from Figure 5.3 ---------------------------------- EXAMPLE OF NESTED DATA STRUCTURES // StudentType.h #ifndef StudentType_h #define StudentType_h 1 typedef char IDNum[10]; const int STRING_CHARS = 20; typedef char String[STRING_CHARS+1]; enum GenderType {male, female, unknown}; enum ClassType {fresh, soph, junior, senior, grad, special}; struct NameType { String first; char middleInit; String last; }; struct StudentType { NameType name; ClassType classific; IDNum socialSecNum; GenderType gender; float gradePtAvg; }; #endif --------------------------- draw picture, or reproduce figure 5.4 to show what a record looks like --------------------------- HOW DO YOU REFER TO ... ? // StudentTypeClient.C #include #include "StudentType.h" int main() { StudentType student; // make the gender be female // make the middle initial be Q // make the first name be "Jane" // make the last name be "Public" // make the soc. sec number be 000...0 } ------------------------------- use several assignments for Jane. use strcpy for Public use for loop for social security number. ---------------------------------- FOR YOU TO DO // StudentTypeClient.C #include #include "StudentType.h" int main() { StudentType student[150]; for (int i = 0; i < 150; i++) { // make the gender be unknown // make the middle initial be A // the first name be "Jon" // make the last name be "Fuddyduddy" // make the soc. sec number be 123...9 } } ------------------------------------- *** problem example (compare HR 5.2-3) ---------------------------------- PROBLEM Find index of first record that has the least name (in alphabetic order) in an array of StudentType records. --------------------------------- strategy: 1. overload operator <= for Name first, use last name, then first and middle, for implementation, use strcmp 2. then write the loop 3. then a test harness... ** type equality is by name for structs ------------------------------------ struct TYPES COMPARED BY NAME // client code struct MilesType { float value; }; extern void PointLaser(MilesType height); int main() { MilesType MtK; MtK.value = 7; PointLaser(MtK); // ok? } // implementation code struct KmType { float value; }; void PointLaser(KmType height) { // ... } ------------------------------------ this is an error in C++, because KmType has a different name from MilesType, even though they have the same fields with the same type this particular error will be caught at link time.. (nothing like MOVE CORRESPONDING in COBOL here) ** syntactic variations useful for programming variants ---------------------------------- SYNTACTIC VARIATIONS (USEFUL LATER) // declaring struct and instances at once struct EmployeeType { char firstInit; char lastInit; int age; GenderType gender; float hourlyWage; } manager, worker1; // declaring instances of unnamed structs struct { int age; float weight; } thisPerson; ---------------------------------- the latter will be useful for programming variants, but otherwise not very useful, because structs compared by name so can't pass anonymous ones around