Class Student Record Student ID First name Last name Gender major GPA How do we store the data? Store Student Records in Variables // For one student at a time float GPA; string firstName, lastName; string major; long id; char gender; … 3 Store Student Records in Parallel Arrays const int MAX_STUDENTS = 100; long string string char string float id [MAX_STUDENTS]; firstName[MAX_STUDENTS]; lastName [MAX_STUDENTS]; gender [MAX_STUDENTS]; major [MAX_STUDENTS]; gpa [MAX_STUDENTS]; C++ Data Types simple integral enum structured floating array struct union class char short int long bool float double long double address pointer reference Store Student Records in Class class Student // “Student” is the identifier of this class { private: // indicates following variables are only accessible within class Student long id; // data fields (something new in class) string firstName; string lastName; char gender; string major; float gpa; public: // indicates following methods can be used outside class Student long GetID ( ) // methods (something new in class) { ... } void SetID ( long id ) { ... } ... // semicolon after } }; C++ Class Syntax: class ClassName { private: DataMemberList; MethodMemberList1; public: MethodMemberList2; }; class, private, and public are key words. A class usually has two types of members: data fields and methods. • Data fields should always be private! • Method can be private or public. (We will explain this later.) Class Object class Student { private: long id; string firstName; ... }; // Student is a new data type! Student stu1; // stu1 is an object of Student. // A class object is a variable of the class! // A Student object is a variable of Student data type! Class Methods class Student { private: long id; ... public: ... void PrintStudentRecord () { cout << setprecision(2) << fixed << endl; cout << setw(8) << id << setw(15) << firstName << setw(15) << lastName << setw(8) << gender << setw(20) << major << setw(8) << gpa; } ... }; How to call this function? You can only call this function if it is public! Declare a class object and then Use the dot notation! Call a Class Method int main() { Student stu; // Declare a Student object first. ... // assume all data fields in stu are filled with values stu.PrintStudentRecord(); // Use DOT notation. ... return 0; } Didn’t we already know classes?! cin >> base; while ( !cin.eof() && (base < 2 || base > 9) ) { // display message cin.ignore(MAX_LINE_SIZE, ‘\n’); cin >> base: } string str1, str2; str1 = “”; while(str1.length() < MAX_LENGTH) { cin >> str2; str1 += str2; } Class Scope The identifier of a class member has class scope and can only be used in the following cases: In a member function of that class After the . (dot) operator applied to an object of that class (if it is declared as public) Other situations (not covered in this class) An identifier declared within a member function hides a declaration of the same identifier whose scope extends to or past the end of the member function's class. Use a data field in a member function class Student { private: long id; string firstName; string lastName; char gender; string major; float gpa; firstName, etc are data fields of Class Student: they can be used directly in member functions of Class Student! public: void PrintStudentRecord () { cout << "Name : " << firstName << "Gender: " << gender << "Major : " << major << "GPA : " << gpa } ... }; << << << << " " << lastName endl endl endl; << endl Call a member function after DOT void main() { Student stu1; ... stu1.PrintStudentRecord(); ... return 0; } PrintStudentRecord is a public method of Class Student: it can be used anywhere outside Class Student by DOT notation. Access private data in a class class Student { private: long id; string firstName; string lastName; char gender; string major; float gpa; ... } int main() { Student stu1; ... cout << stu1.id; ... } No! DOT notation cannot be used to access private data or methods! // The data fields are private to a Student object. What if we want to use their values in the main function? Access private data in a class class Student { private: long id; string firstName; string lastName; char gender; string major; float gpa; public: long GetID() { return id; } int main() { Student stu1; ... cout << stu1.GetID(); ... } Declare a public method to access private data! } // The data fields are private to a Student object. What if we want to use their values in the main function? Input values to data fields Student stu1; ... stu1.firstName = “Alex”; // NO! firstName is private! stu1.SetFirstName(“Alex”); // Yes! Declare a Set method to input values to private data fields! class Student { private: string firstName; ... public: void SetFirstName(string fname) { firstName = fname; } ... } Initialize a class object // Declare variable with initial value int numStudents = 0; // Can we declare a class variable with initial value? Student s1; Use Class Constructors! Class Constructor class Student { private: long id; char gender; string firstName, lastName, major; float gpa; public: Student() // Default { id = 1001; firstName = “Alice”; lastName = “Wonderland”; gender = ‘F’; major = “ComputerScience”; gpa = 3.2; } }; // Syntax for constructor // No returned data type! constructor: no parameters! Class Constructor With Parameters class Student { private: long id; char gender; string firstName, lastName, major; float gpa; public: Student( long stuId, string fName, string lName, char stuGender, string stuMajor, float stuGpa ) { id = stuId; firstName = fName; The parameter names cannot lastName = lName; be the same as data fields! gender = stuGender; why? major = stuMajor; gpa = stuGpa; } }; Multiple Class Constructors class Student { ... public: Student( ) { id = 1001; firstName = "Alice"; lastName = "Wonderland"; gender = 'F'; major = "ComputerScience"; gpa = 3.2; } You can define multiple constructors for the same class. Different Constructors Must Have Different Parameters. Which one to use depends on the parameters during the object declaration. Student( long id, string fName, string lName, char stuGender, string stuMajor, float stuGpa ) { id = id; firstName = fName; lastName = lName; gender = stuGender; major = stuMajor; gpa = stuGpa; } ... }; Invoke Class Constructor Constructor is called implicitly when class objects are declared. // Default constructor is called Student stu1; // Parameterized constructor is called Student stu2( 1002, "Johnny", "Depp", 'M', "SoftwareEngineering", 2.8 ); //OR //Student stu2; //stu2 = ( 1002, "Johnny", "Depp", 'M', "SoftwareEngineering", 2.8 ); // The default constructor has set the // values for data members stu1.PrintStudentRecord(); // The parameterized constructor has set the // values for data members stu2.PrintStudentRecord(); // This will change the data fields stu1.SetID(); Different parameters for different constructors // will this work? NO! // will this work? YES! class Student class Student { { private: private: long id; long id; ... ... public: public: Student( long stuID ) Student( long stuID ) { { id = stuID; id = stuID; } } Student( long sID) Student( int stuID ) { { id = sID; id = stuID; gender = ‘F’; } } ... ... }; }; DIFFERENT refers to different data types and number of parameters, not names! Default Constructor // Default constructor is called Student stu1; If you don’t define any constructor: There is a default constructor doing nothing generated by the compiler If you define a constructor without any parameter: This is your new default constructor If you define a constructor with parameters: There is NO default constructor generated by the compiler anymore! Copy Constructor Declare an object which is exactly the same as another object: class Student { ... public: Student( Student stu ) // Copy constructor: { // gets initial values from object stu id = stu.id; firstName = stu.firstName; // Use the DOT notation to access lastName = stu.lastName; // the data field of stu! gender = stu.gender; major = stu.major; gpa = stu.gpa; } ... }; Constructor Summary Define a constructor: NO returned-data type! Constructors have the SAME name as the class! Purpose: initialize a class object Default constructor: NO parameters. If no constructor is defined, a default constructor doing NOTHING will be automatically generated. If there is any parameterized constructor defined, no automatic generated default constructor anymore. Copy constructor: Initialize one object by copying data fields of another object. Use the DOT notation directly to access data fields of another object. Multiple constructors: Different constructors have DIFFERENT parameters! Different constructors are called based on the parameters during object declaration. Invoke constructor: Student stu1; // call the default constructor Student stu2( 1002, "Johnny", "Depp", 'M', "SoftwareEngineering", 2.8 ); Student stu4; stu4 = Student( 1004, “Brad”, “Pitt”, ‘M’, “CS”, 3.6 ); Array of Class Objects Student stuList[MAX_STUDENTS]; // An array of Student objects Each element is treated the same way as a Student object! Everything applied to an integer array applied to an object array! Operations on an object array element Student stuList[MAX_STUDENTS]; Initialization: stuList[i] = Student(stuList[i-1]); Assignment: stuList[i].SetID(1001); Computation: totalGPA += stuList[i].GetGPA(); Pass an object array as a parameter Student stuList[MAX_STUDENTS]; // Given a student id, find the index of the student // in the Student array. Return -1 if not found. // Parameters: in, in, in int FindIndex ( const Student sList[], int size, long id ) { for ( int i = 0; i < size; i ++ ) if ( sList[i].GetID() == id ) return i; return -1; } StudentList Class class StudentList { private: Student stuList[MAX_STUDENTS]; // An array of Students int numStudents; public: StudentList() { numStudents = 0; } ... }; // Treat an element of stuList the same way as a Student object! // // Initialize a stuList element using constructor. Print a stuList element by its PrintRecord() method. StudentList Class class StudentList { private: Student stuList[MAX_STUDENTS]; int numStudents; public: StudentList() { numStudents = 0; } void Read( int size ) { long id; string firstName, lastName, major; char gender; float gpa; if ( size <= MAX_STUDENTS ) while ( numStudents < size ) { cin >> id >> firstName >> lastName >> gender >> major >> gpa; stuList[numStudents] = Student(id, firstName, lastName, gender, major, gpa); numStudents ++; } StudentList( int size ) { numStudents = 0; Read(size); } void Print() { for( int i = 0; i < numStudents; i++ ) stuList[i].PrintRecord(); } } }; Read() is used in the constructor before its definition! StudentList Class class StudentList { private: Student stuList[MAX_STUDENTS]; int numStudents; public: void Read( int size ) { long id; string firstName, lastName, major; char gender; float gpa; if ( size <= MAX_STUDENTS ) while ( numStudents < size ) { cin >> id >> firstName >> lastName >> gender >> major >> gpa; stuList[numStudents] = Student(id, firstName, lastName, gender, major, gpa); numStudents ++; } } void Print() { for( int i = 0; i < numStudents; i++ ) stuList[i].PrintRecord(); } StudentList() { numStudents = 0; } StudentList( int size ) { numStudents = 0; if ( size <= MAX_STUDENTS ) Read(size); } }; Another way to read into a Student List // Suppose Student has a ReadRecord method void Read( int size ) { if ( size <= MAX_STUDENTS ) while ( numStudents < size ) { stuList[numStudents].ReadRecord(); numStudents ++; } // This is a better approach because } // operations related to one object // should be done by that object! // DECOMPOSITION!! Information Hiding Hide data fields and supportive methods under private. Only methods that will be used by other classes or stand alone functions are public. Treat your class object as a BLACK BOX: data fields Class Object supportive methods public methods Helper methods are those only used by member methods in the same class. Employee Class class Employee { private: string employeeID; string firstName; string lastName; float payRate; float weeklyHours; float weeklySalary; void CalcSalary() { if ( weeklyHours <= OVERTIME ) weeklySalary = payRate * weeklyHours; else weeklySalary = OVERTIME_RATE * payRate * (weeklyHours - OVERTIME ) + payRate * OVERTIME; } public: void Print () { CalcSalary(); cout << "ID : << "Name : << "Pay Rate: << "Hours : << "Salary : } } " " " " " << << << << << employeeID << endl firstName << " " << lastName payRate << endl weeklyHours << endl weeklySalary << endl << endl; << endl Class Method Modifier const class Student { private: long id; string firstName, lastName, major; char gender; float gpa; public: // The method will NOT change any data members: const. // It cannot call a non-const member functions! void PrintRecord () { cout << "Name : << "Gender: << "Major : << "GPA : } const " " " " << << << << firstName gender major gpa << << << << " " << lastName endl endl endl; << endl // The method will change some data members: no const. void ReadRecord () { cin >> id >> firstName >> lastName >> gender >> major >> gpa; } }; Class Method Modifier const class Student { private: long id; string firstName, lastName, major; char gender; float gpa; public: void Write() const float GetGPA() const string GetFirst() const // No const void Read() void SetGPA( float value ) void UpdateGPA( float amount ) . . . }; Comparing Objects Student stu1, stu2; stu1.ReadRecord(); stu2.ReadRecord(); // Check if stu1’s GPA is higher than stu2 if ( stu1.GetGPA() > stu2.GetGPA() ) cout << stu1.GetFirstName() << " has higher GPA than " << stu2.GetFirstName() << endl; Comparing Method class Student { ... public: // Use a Student object as a parameter! bool HasHigherGPA ( Student stu ) const { return ( gpa > stu.gpa ); } }; Pass Objects as Parameters Basic Data Types (char, int, float, string, bool) Pass by Value (without & in prototype) Pass by Reference (with & in prototype) Arrays (of any data type) Always Pass by Reference (Never &) Class Object (and structure) C++ allows pass by value (no &) and by reference (&) Our Rule: Always pass by reference with & Use const for in parameter Comparing Method class Student { ... public: // Pass by reference // Use const to make sure stu will not be changed bool HasHigherGPA ( const Student& stu ) const { return ( gpa > stu.gpa ); } }; Re-Visit Copy Constructor class Student { ... public: // Copy constructor: // gets initial values from object s // Will change data members: no const. // Will not change parameter s: const with & Student( const Student& stu ) { id = stu.id; firstName = stu.firstName; lastName = stu.lastName; gender = stu.gender; major = stu.major; gpa = stu.gpa; } ... }; More methods in StudentList class StudentList { ... public: int Find( const Student& stu ) const int Find( long stuID ) const int Find( string fName, string lName ) const // Similar as multiple constructors, a class can also // have multiple methods with the same name, // but DIFFERENT parameters! void GetStats( float& max, float& min, float& average ) const void UpdateGPA ( long id, float gpa ) ... }; // See studentList3.cpp for details Design your class What should be included in your class (Student)? treat your class as a real world entity. attributes related to the class: gpa, major, etc. operations that can be initiated by the class: read, write, get, set, calculate, etc. For class Student, should “find”, “add”, “delete”, “sort” be its methods? NO! They are not initiated and manageable by Student. Summary class private and public members data fields and operations class constructor class objects array of class objects pass object as a function parameter class method modifier const class for a list switch statement const const const const const float float float float float A_GRADE B_GRADE C_GRADE D_GRADE F_GRADE = = = = = 4.0; 3.0; 2.0; 1.0; 0.0; char grade; cin >> grade; cout << endl << "Your grade is " << fixed << setprecision(1); if ( grade == ‘A’) cout << A_GRADE; else if ( grade == ‘B’ ) cout << B_GRADE; else if ( grade == ‘C’ ) cout << C_GRADE; else if ( grade == ‘D’ ) cout << D_GRADE; else if ( grade == ‘F’ ) cout << F_GRADE; else cout << “not valid!”; char grade; cin >> grade; cout << endl << "Your grade is " << fixed << setprecision(1); switch( grade ) { case 'A': cout << A_GRADE; break; case 'B': cout << B_GRADE; break; case 'C': cout << C_GRADE; break; case 'D': cout << D_GRADE; break; case 'F': cout << F_GRADE; break; default : cout << "not valid!"; } switch statement Syntax: switch (IntegralOrEnumExpression) { case ConstantExpression: statement1 ... default: statementN } switch, case and default are key words. break; is used to stop execution and go directly to the end of the statement block. (optional) C++ Data Types simple integral enum structured floating array struct union class char short int long bool float double long double address pointer reference Store Student Records in Structure struct Student { long id; string firstName; string lastName; char gender; string major; float gpa; }; // Now Student is a Data Type! C++ Struct (Record) Syntax: struct TypeName { MemberList; }; Struct is a heterogeneous structured data type: each individual component is called a field they can be of different data types Declare a struct before the function prototypes after the constant declarations Everything needs to be declared before used! Declare a Structure Student const int MAX_STUDENTS = 100; struct Student { long id; string firstName; string lastName; char gender; string major; float gpa; }; int ReadRecord ( int maxSize, Student record[] ); void OutputRecord ( long stuID, int size, const Student record[] ); int SearchID ( const Student record[], int size, long target ); int main() { Student stuRecord[MAX_STUDENTS]; //… } //Since Student is a data type, we can also make an array of Student! Accessing Members of a Structure Use the dot notation. Student stu1; // Input data into struct cout << "Enter ID: "; cin >> stu1.id; cout << "Enter first name: "; cin >> stu1.firstName; // Output student data cout << setw(8) << stu1.id << setw(15)<< stu1.firstName; Substitute Parallel Arrays with Structure: Read //-------------------------------------------------------------// The function reads student records from an input file into different arrays and // count the actual number of input records. Once the user input maxSize elements, // the function will stop reading the input. It returns the actual number of records. // Parameters: (in, out) //-------------------------------------------------int ReadRecord ( int maxSize, Student record[] ) { ifstream inData; inData.open ( "student-record.in" ); int size = 0; inData >> record[size].id >> record[size].firstName >> >> record[size].gender >> record[size].major >> while ( !inData.eof() && size < maxSize ) { size ++; inData >> record[size].id >> record[size].firstName >> record[size].gender >> record[size].major } inData.close(); return size; } record[size].lastName record[size].gpa; >> record[size].lastName >> record[size].gpa; Substitute Parallel Arrays with Structure: Search // Parameters: (in, in, in) //-----------------------------------------------int SearchID ( const Student record[], int size, long target ) { for ( int i = 0; i < size; i++ ) { if ( record[i].id == target ) return i; } return -1; } Substitute Parallel Arrays with Structure: Output //------------------------------------------------------------------// The function takes the student id and total number of records // as inputs. If there exists a record with that student id, // the function will print out the student's id, name, gender, major, // and gpa; otherwise, it will print a "Not found" message. // Parameters: ( in, in, in ) //------------------------------------------------------------------void OutputRecord ( long stuID, int size, const Student record[] ) { int index; index = SearchID ( record, size, stuID ); if ( index != -1 ) { cout << "Name : " << record[index].firstName << " " << record[index].lastName << endl << "Gender: " << record[index].gender << endl << "Major : " << record[index].major << endl << "GPA : " << record[index].gpa << endl; } else cout << "The student record does not exist!" << endl; }