1 Chapter 4 CLASSES AND OBJECTS
2 Outlines Procedural vs. Object ‑ Oriented Programming C++ Structures versus C Structures Classes –Accessing Class Members –Member Functions –Allocating Objects Dynamically Constructor and Destructor Functions –Constructors –The Class Destructor Case Study: Data Encryption
3 4-1 Procedural versus Object ‑ Oriented Programming Applying procedural or structured concepts in a large, complex program may lead to a variety of problems such as –Difficulty in maintaining and modifying the program. –Many details easily can disorganize and overload the programmer. –Difficulty in debugging the program and following its logic. –Creation of logic errors such as inadvertent data modification.
4 Object An object is a single entity that groups together related data and functions that operate on that data.
5 Communication Some functions can be used as utility functions within the object while the others serve as interface functions to communicate with other objects within a program.
6 OOP An OOP program can be described as a collection of objects that communicate with each other through their interface functions. The communication between objects is commonly described as sending messages to objects.
7 OOP Concept Encapsulation( 封裝 ) is the concept of binding together data and functions into one capsule or object. –This concept is also known as data abstraction. –Its implementation enables data hiding, which means an object can hide its data from the rest of the program and provide access to the data only through its interface functions. –This reduces the possibility of inadvertent data modification and various kinds of logic errors. –OOP technology facilitates code reusability much more efficiently than procedural technology.
8 OOP Concept Inheritance( 繼承 ) is one of the most important OOP tools in the implementation of code reusability. –When using inheritance, new code can be derived or inherited from existing code. –This reduces the amount of coding and the size of the program. Polymorphism( 多形 ) is the concept of using the same functions on different types of objects. –This OOP tool enables C++ programmers to reduce program development time.
9 4-2 C++ STRUCTURES VERSUS C STRUCTURES Structures are used in C programming to group related variables together. Example : struct circuit { //structure declaration char description[l0]; int quantity; float impedance; // 組抗 }; //structure variable declarations in C struct circuit amplifier, speaker;
10 Difference C: struct should be used to define the variable C++: no need struct. //structure variable declarations in C struct circuit amplifier, speaker; //structure variable declarations in C++ circuit amplifier, speaker;
11 Dot separator (.) a dot separator (.) is used to separate the structure variable name from its member variable as shown in the following examples: speaker.impedance = 8; amplifier.quantity = 1; cout«amplifier.description;
12 Example PROBLEM: Compute for how long a battery can deliver a certain amount of current I to a device (load) at the rated voltage. The battery's voltage V b and capacity (ampere ‑ hour rating), as well as the impedance Z of the device are given. SOLUTION: –If given V b =12 V, capacity=20 Ah, Z=50Ω, –I=V b /Z=12/50=0.24A –Time=capacity/I=20/0.24=83.33 h
13 #include //using namespace std; struct Battery { //structure declaration float voltage; float capacity; }; void setValues(Battery &); //reference to a structure as a void getValues(Battery &); //function parameter float getHours(Battery &, float); int main() { float imp=50; //device impedance Battery b; //structure variable setValues(b); //passing structure variable by reference cout<<endl; getValues(b); cout<<"Device can be powered "<<getHours(b,imp)<<" hours."; return 0; }
14 void setValues(Battery &rb) //Gets battery's voltage and capacity from the user { cout >rb.voltage; cout >rb.capacity; } void getValues(Battery &rb) //Displays battery voltage and capacity { cout<<setiosflags(ios::fixed)<<setprecision(1); cout<<"Voltage = "<<rb.voltage<<" [V]"<<endl; cout<<"Capacity = "<<rb.capacity<<" [Ah]"<<endl; } float getHours(Battery &rb, float imp) //Computes and returns the time { float current = rb.voltage/imp; return rb.capacity/current; }
15
Structure Definitions Structures –Aggregate data types built using elements of other types ,不同 型態資料的集合。 struct Time { int hour; int minute; int second; }; –Members of the same structure must have unique names –Two different structures may contain members of the same name –Each structure definition must end with a semicolon Structure tag Structure members
17 Structure Definitions Self-referential structure –Structure 中任一個 member 的資料型態都不能為該 structure 本身。 –Contains a member that is a pointer to the same structure type. –Used for linked lists, queues, stacks and trees struct –Creates a new data type that is used to declare variables. –Structure variables are declared like variables of other types. –Example: Time timeObject, timeArray[ 10 ], *timePtr, &timeRef = timeObject
18 Accessing Members of Structures Member access operators: –Dot operator (.) for structures and objects –Arrow operator (->) for pointers –Print member hour of timeObject: cout << timeObject.hour; cout << timeRef.hour; OR timePtr = &timeObject; cout hour; –timePtr->hour is the same as ( *timePtr ).hour –Parentheses required: * has lower precedence than.
19 2. Create a struct data type 1// Fig. 6.1: fig06_01.cpp 2// Create a structure, set its members, and print it. 3#include 4 5using std::cout; 6using std::endl; 7 8struct Time { // structure definition 9 int hour; // int minute; // int second; // }; 13 14void printMilitary( const Time & ); // prototype 15void printStandard( const Time & ); // prototype 16 17int main() 18{ 19 Time dinnerTime; // variable of new type Time // set members to valid values 22 dinnerTime.hour = 18; 23 dinnerTime.minute = 30; 24 dinnerTime.second = 0; cout << "Dinner will be held at "; 27 printMilitary( dinnerTime ); 28 cout << " military time,\nwhich is "; 29 printStandard( dinnerTime ); 30 cout << " standard time.\n"; 31 Creates the user-defined structure type Time with three integer members: hour, minute and second. Dinner will be held at 18:30 military time, which is 6:30:00 PM standard time.
20 32 // set members to invalid values 33 dinnerTime.hour = 29; 34 dinnerTime.minute = 73; cout << "\nTime with invalid values: "; 37 printMilitary( dinnerTime ); 38 cout << endl; 39 return 0; 40} 41 42// Print the time in military format 43void printMilitary( const Time &t ) 44{ 45 cout << ( t.hour < 10 ? "0" : "" ) << t.hour << ":" 46 << ( t.minute < 10 ? "0" : "" ) << t.minute; 47} 48 49// Print the time in standard format 50void printStandard( const Time &t ) 51{ 52 cout << ( ( t.hour == 0 || t.hour == 12 ) ? : t.hour % 12 ) 54 << ":" << ( t.minute < 10 ? "0" : "" ) << t.minute 55 << ":" << ( t.second < 10 ? "0" : "" ) << t.second 56 << ( t.hour < 12 ? " AM" : " PM" ); 57} Time with invalid values: 29:73
21 C++ struct The structure type has been expanded in C++. It can also include functions as structure members along with the data they process. Structure members (variables or functions) that follow the private keyword are private to that structure ‑ i.e., they can be accessed only by other members of the same structure. Public structure members can be used/accessed outside the structure.
22 //PROG4_2. An improved version of the program PROG4_1, which // uses an expanded Battery structure. #include using namespace std; struct Battery { void setValues() //functions as public structure members { cout<<"Enter battery voltage: "; cin>>voltage; cout<<"Enter battery capacity: "; cin>>capacity; } void getValues() { cout<<setiosflags(ios::fixed)<<setprecision(1); cout<<"Voltage = "<<voltage<<" [V]"<<endl; cout<<"Capacity = "<<capacity<<" [Ah]"<<endl; }
23 float getHours(float imp) { float current=voltage/imp; return capacity/current; } private: float voltage; //private data members float capacity; }; int main() { float imp=50; Battery b; b.setValues(); //calling a structure member function cout<<endl; b.getValues(); cout<<"Device can be powered "<<b.getHours(imp)<<" hours."; return 0; }
24 Example Struct_var.function_name(); No need argument; Simplification of the program's logic and reduction of its complexity. Easier modification and maintenance of the program. Protection of data from inadvertent changes.
25 C vs C++ A C++ structure may contain both functions and data, unlike C structures that contain data only. Data can be protected or hidden by using the private access specifier. It is not necessary to use the struct keyword when instantiating variables.
Classes The class is a foundation of OOP It is very similar to the expanded structures that group related data and functions together.
27 Class Object_list: optional Class member –Member variables, also called data members –Member functions Class is used to create object. Object is an instance of class. –data members can be viewed as the object's attributes or properties, – member functions describe its behavior or methods.
28 1class Time { 2public: 3 Time(); 4 void setTime( int, int, int ); 5 void printMilitary(); 6 void printStandard(); 7private: 8 int hour; // int minute; // int second; // }; Implementing a Time Abstract Data Type with a Class Classes –Model objects that have attributes (data members) and behaviors (member functions) –Defined using keyword class –Have a body delineated with braces ({ and }) –Class definitions terminate with a semicolon –Example: Public: and Private: are member-access specifiers. setTime, printMilitary, and printStandard are member functions. Time is the constructor. hour, minute, and second are data members.
29 Implementing a Time Abstract Data Type with a Class Member access specifiers –Classes can limit the access to their member functions and data. –The three types of access a class can grant are: Public — Accessible wherever the program has access to an object of the class. private — Accessible only to member functions of the class 或 friend class 。 Protected — Similar to private Constructor –Special member function that initializes the data members of a class object. –Cannot return values –Have the same name as the class
30 Forward reference The class keyword can also be used to create a forward reference to inform the compiler that the identifier that follows is a class type. Where a class name or identifier precedes the class definition, a forward reference is required. class Spacecraft; //forward reference where Spacecraft is a class name/identifier. Spacecraft challenger; //challenger is an object of the class Spacecraft
31 ACCESSING CLASS MEMBERS C++ provides three ways of accessing class members. The way a class member is accessed is specified by one of the following member access specifiers: –Private : can only be accessed by other members of the same class. –Public : can be accessed by members of its class as well as members of any other class and non ‑ member functions, including main() –Protected : Chapter 7 when dealing with inheritance
32 Access member An access specifier followed by a colon (:) should be placed before a class member declaration. Members with the same access should be grouped together and listed after their access specifier. Unlike structure members, the default access specifier for class members is private. If the private members are listed first in a class definition, the access specifier can be omitted. To improve clarity, the program should explicitly use private to denote access.
33 Class definition class Jet{ float acc, vel, dis; //acceleration, velocity, displacement float getTime() {//Computes the time during which return vel/acc;//the jet is being accelerated } public: void setValues(float x, float y) { acc=x;vel=y; //Sets the acceleration and velocity } float getDisplacement() { return (vel*getTime())/2; //Returns the displacement. }//of the jet13 };
34 Class Public class member can be accessed outside through a class object using the general format: Object.class_member It should be noted that an object is not needed to access a class member by another member of the same class
35 int main() { Jet plane;//Instantiates an object plane.setValues(40, 65);//Calls a member function cout «"The time during which the plane "; cout «"is being accelarated = "; cout « plane.getTime();//ERROR!!! (private) cout «"\n The plane's displacement = "; cout «plane.getDisplacement(); return 0; }
36 Member function A member function is a function that is a member of a class. Member functions are usually used to manipulate class data members, and in most cases provide the only way to access the private class data. A member function can be either an inline or non ‑ inline function. To create an inline member function, it is only necessary to place the function's definition inside the class. –long functions, recursive functions, and functions containing loops or static variables cannot be expanded inline.
37 Non-inline If a member function falls into one of these categories (long, Recursive, …) and its definition is placed within the body of the class, the compiler will usually issue a warning message and process the function as a non ‑ inline member function. Non ‑ inline member functions have their prototypes inside the class and definitions outside the class.
38
39 //PROG4_3: Computes the resistance for specified color bands. // Uses a class with inline and non-inline // member functions. #include using namespace std; class Resistor { private: int band1, band2, band3, band4; int resistance; public: void getValues(); //non-inline function prototype void calcResistance() { //inline function definition resistance=(((band1*10)+band2)*pow(10,band3)); } void printResistance(); //non-inline function prototype }; //End of class definition
40 void Resistor::getValues() //non-inline function definition { cout "; cin >> band1; cout "; cin >> band2; cout "; cin >> band3; cout "; cin >> band4; }
41 void Resistor::printResistance() { //non-inline function definition char *tolerance; calcResistance(); //Calls a member function if( band4 == 10 ) tolerance = "+/- 5%"; if( band4 == 11 ) tolerance = "+/- 10%"; if( band4 == 12 ) tolerance = "+/- 20%"; cout<<"\n\n The resistance is "<<resistance<< " ohms"; cout<<" with "<< tolerance<<" tolerance." << endl; }
42 int main() { Resistor res; //Instantiates an object res.getValues(); //Calls a member function res.printResistance(); //Calls a member function return 0; }
Implementing a Time Abstract Data Type with a Class Class definition and declaration –Once a class has been defined, it can be used as a type in object, array and pointer declarations –Example: Time sunset, // object of type Time arrayOfTimes[ 5 ], // array of Time objects *pointerToTime, // pointer to a Time object &dinnerTime = sunset; // reference to a Time object Note: The class name becomes the new type specifier. 用 class 宣告出來的變數稱為 object 。
44 1// Fig. 6.3: fig06_03.cpp 2// Time class. 3#include 4 5using std::cout; 6using std::endl; 7 8// Time abstract data type (ADT) definition 9class Time { 10public: 11 Time(); // constructor 12 void setTime( int, int, int ); // set hour, minute, second 13 void printMilitary(); // print military time format 14 void printStandard(); // print standard time format 15private: 16 int hour; // 0 – int minute; // 0 – int second; // 0 – 59 19}; 20 21// Time constructor initializes each data member to zero. 22// Ensures all Time objects start in a consistent state. 23Time::Time() { hour = minute = second = 0; } 24 25// Set a new Time value using military time. Perform validity 26// checks on the data values. Set invalid values to zero. 27void Time::setTime( int h, int m, int s ) 28{ 29 hour = ( h >= 0 && h < 24 ) ? h : 0; 30 minute = ( m >= 0 && m < 60 ) ? m : 0; 31 second = ( s >= 0 && s < 60 ) ? s : 0; 32} Note the :: preceding the function names. Construct 作初值化 Member function 的型態 宣告在 class 裡面,而定 義常寫在 class 外面 設定時間的涵數,作 了一些正確性檢查的 動作
// Print Time in military format 35void Time::printMilitary() 36{ 37 cout << ( hour < 10 ? "0" : "" ) << hour << ":" 38 << ( minute < 10 ? "0" : "" ) << minute; 39} 40 41// Print Time in standard format 42void Time::printStandard() 43{ 44 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 ) 45 << ":" << ( minute < 10 ? "0" : "" ) << minute 46 << ":" << ( second < 10 ? "0" : "" ) << second 47 << ( hour < 12 ? " AM" : " PM" ); 48} 49 50// Driver to test simple class Time 51int main() 52{ 53 Time t; // instantiate object t of class Time cout << "The initial military time is "; 56 t.printMilitary(); 57 cout << "\nThe initial standard time is "; 58 t.printStandard(); 59 Notice how functions are called using the dot (. ) operator. The initial military time is 00:00 The initial standard time is 12:00:00 AM
46 60 t.setTime( 13, 27, 6 ); 61 cout << "\n\nMilitary time after setTime is "; 62 t.printMilitary(); 63 cout << "\nStandard time after setTime is "; 64 t.printStandard(); t.setTime( 99, 99, 99 ); // attempt invalid settings 67 cout << "\n\nAfter attempting invalid settings:" 68 << "\nMilitary time: "; 69 t.printMilitary(); 70 cout << "\nStandard time: "; 71 t.printStandard(); 72 cout << endl; 73 return 0; 74} The initial military time is 00:00 The initial standard time is 12:00:00 AM Military time after setTime is 13:27 Standard time after setTime is 1:27:06 PM After attempting invalid settings: Military time: 00:00 Standard time: 12:00:00 AM Military time after setTime is 13:27 Standard time after setTime is 1:27:06 PM After attempting invalid settings: Military time: 00:00 Standard time: 12:00:00 AM
47 Implementing a Time Abstract Data Type with a Class Destructors –Functions with the same name as the class but preceded with a tilde character (~) –Cannot take arguments and cannot be overloaded –Performs “termination housekeeping” Binary scope resolution operator (::) –Combines the class name with the member function name –Different classes can have member functions with the same name Format for defining member functions ReturnType ClassName::MemberFunctionName( ){ … }
48 ALLOCATING OBJECTS AT RUN ‑ TIME A class object or an array of objects can be dynamically allocated at run ‑ time in the same way as ordinary variables of built ‑ in types. –A pointer of the class type and the new operator are needed to perform this operation. –The delete operator is used to free memory dynamically allocated to store class object(s).
49 int main() { int num, i; cout «"How many resistors? "; cin»num; Resistor *ptres=new Resistor[num]; //Allocating objects dynamically if(!ptres) { cout «"Memory Allocation Error!"; exit(1); } for(i=0; i<num; i++) { cout«"\nResi stor # "«(i+1)«endl ; ptres[i].getValues(); ptres[i].printResistance(); } delete []ptres; return 0; }
Constructor and Deconstructor Initializing variables before they are used is a common programming practice. Provides a special kind of member function called the constructor function, which is a more convenient tool to perform initialization than using functions. A constructor function can perform any kind of operation just like any other member function. It is a common programming method, however, to use constructors to initialize class data members. A constructor function has the following properties or characteristics: –It has the same name as the class for which it is designed. –It has no return type, not even void. –It can have arguments, including default arguments. –Unlike other member functions, it is never explicitly called. A constructor function is automatically called whenever an object is declared.
51 Constructor When using constructors, it is also important to know the following: –Constructors should be public, so they can be called outside the class ‑ including main(). –A class can have as many constructors as necessary ‑ i.e., they can be overloaded. –Constructors cannot be inherited (inheritance will be discussed in Chapter 7). –Each class should have its own constructors
52 Example class Battery { float voltage = 12.0; //ERROR! This cannot be done here. float capacity; public: // member functions } The initialization should be done by a constructor function. Battery ()//default constructor { voltage = 12.0; capacity = 30.0; } This constructor function is called a default constructor, because it assigns default values to the class data members. –No parameters, no return types, name as class.
53 Constructor When an object of the class is declared, the constructor is automatically called. Battery bt;//Calling default constructor With parameters Battery(float v, float c)//constructor with arguments { voltage = v; capacity = c; } When calling this constructor, two arguments should be passed to the function. Battery bt(12.0, 30.0); //Calling constructor and passing arguments
54 Constructor with default argument A constructor function may use default arguments, Battery(float v = 12.0, float c = 30.0)//constructor with {//default arguments voltage = v; capacity = c; } Battery bt1; //use default value Battery bt2(5.0, 20.0); //Overrides default values
55 Destructor Constructor functions do their construction job when class objects are instantiated. Although they commonly initialize class objects, constructors are also frequently used to perform other operations as well ‑ an example of which is dynamically allocating memory for class data members. There is a need, therefore, to do a cleaning when objects are destroyed. C++ provides a special member function called the destructor function that is the complement of a constructor function. It is automatically called when an object is destroyed. The destructor function is needed to clean up the class object when it goes out of scope.
56 Properties of destructor function Its name is the tilde(~) character followed by the class name. It cannot have a return type. It cannot have arguments. It is automatically called when an object goes out of scope.
57 ~ErrMessage() {delete []mes;} //destructor
58 //PROG4_4: Demonstrates a use of the overloaded constructor and // destructor functions. #include using namespace std; class Battery { private: float voltage; float capacity; public: Battery() { //default constructor voltage=12; capacity=20; }
59 Battery(float v, float cp) { //constructor with arguments voltage=v; capacity=cp; } void getValues(){ cout<<setiosflags(ios::fixed)<<setprecision(1); cout<<"Voltage = "<<voltage<<" [V]"<<endl; cout<<"Capacity = "<<capacity<<" [Ah]"<<endl; } float getHours(float imp) { float current=voltage/imp; return capacity/current; } ~Battery(){ cout<<"\nBattery discharged!!!"; } //destructor };
60 int main() { float imp=100; //device impedance { Battery b1; //Calls default constructor cout<<"First battery: "<<endl; b1.getValues(); cout<<"Device can be powered "<<b1.getHours(imp); cout<<" hours."<<endl; } //Calls destructor to destroy b1 Battery b2(12,10); //Calls constructor with arguments cout<<"\n\nSecond battery: "<<endl; b2.getValues(); cout<<"Device can be powered "<<b2.getHours(imp); cout<<" hours."<<endl; return 0; //Calls destructor }
61
Case Study The program should first obtain a message up to 80 characters long from the user and then encrypt the message. It should then offer the user an option to either view the encrypted message or view the original message. The original message should be password protected ‑ that is, the user should enter a correct password in order to view the original message. The number of attempts to enter the password should be limited to three.
63 INPUT/OUTPUT Requested input from the user: –A message up to 80 characters long –A selection of one of the following options: View the encrypted message View the original message Exit the program –If the option to view the original message is selected, a password up to six characters long should be required.
64
65 Main
66 //CASEST4: Program demonstrates a data encryption technique and // a class with a constructor and destructor. #include using namespace std; class Encryption { char *message; char password[7]; int mask; public: Encryption(char *); //constructor ~Encryption(){ //destructor delete []message; cout<<"\nMessage destroyed!\n"; } void encryptDecrypt(); bool getPassword(); void getOption(); void printMessage() { cout<<"\n\nMessage: "<<message<<endl; } };
67 Encryption::Encryption(char *tmes) { //Allocates memory dynamically int n=strlen(tmes); //and initializes data members message = new char[n+1]; if(!message) { cout<<"Memory Allocation Error!"; exit(1); } strcpy(message,tmes); strcpy(password," "); mask = rand(); } void Encryption::encryptDecrypt() //Encrypts/decrypts a { //message for (int i=0; i<strlen(message); i++) { message[i]^=mask; }
68 bool Encryption::getPassword() //Gets password from the user { //and checks if correct int cnt=3; char pass[7]="SENECA"; do { cout "; cin>>password; if(strcmp(pass, password)) { cout<<"\nInvalid Password! "; cout<<(cnt-1)<<" attempt(s) left!\n"; } cnt--; }while(cnt>0 && strcmp(pass, password)); if(!strcmp(pass,password)) return true; else return false;}
69 void Encryption::getOption() //Gets a selection from the user { //and executes the operation int option; //selected by the user char c; do { cout<<"\nOptions:"; cout<<"\n\t1. View encrypted message"; cout<<"\n\t2. View original message"; cout<<"\n\t3. Exit"; cout "; cin>>option; }while (option 3); } if(option==1) { printMessage(); cout "; cin>>c; if(c=='y'||c=='Y') { if(getPassword()) { encryptDecrypt(); printMessage(); } else cout<<"\n\nInvalid password!\n"; } if(option==2) { if(getPassword()) { encryptDecrypt(); printMessage(); } else cout<<"\nInvalid password!\n"; }
70 int main() { char tmes[81]; srand(time(0)); cout<<"\nEnter a message to encrypt (up to 80 "; cout "; cin.getline(tmes,80); Encryption text(tmes); //Instantiates an object text.encryptDecrypt(); //Calls member functions text.getOption(); return 0; } //Executes the destructor automatically
71 Output
72 Class Scope and Accessing Class Members Function scope –Variables only known to function they are defined in –Variables are destroyed after function completion –Data member 與 member function 中所宣告的變數名稱相同的話, 在涵數中、 data member 會被遮住,可以加上 class 名稱與 scope resolution operator(::) 讀取。 Accessing class members –Same as struct –Dot (.) for objects( 或 reference to an object) and arrow (->) for pointers –Example: t.hour is the hour element of t TimePtr->hour is the hour element
73 1. Class definition 2. Create an object of the class 2.1 Assign a value to the object. Print the value using the dot operator 2.2 Set a new value and print it using a reference 1// Fig. 6.4: fig06_04.cpp 2// Demonstrating the class member access operators. and -> 3// 4// CAUTION: IN FUTURE EXAMPLES WE AVOID PUBLIC DATA! 5#include 6 7using std::cout; 8using std::endl; 9 10// Simple class Count 11class Count { 12public: 13 int x; 14 void print() { cout << x << endl; } 15}; 16 17int main() 18{ 19 Count counter, // create counter object 20 *counterPtr = &counter, // pointer to counter 21 &counterRef = counter; // reference to counter cout << "Assign 7 to x and print using the object's name: "; 24 counter.x = 7; // assign 7 to data member x 25 counter.print(); // call member function print cout << "Assign 8 to x and print using a reference: "; 28 counterRef.x = 8; // assign 8 to data member x 29 counterRef.print(); // call member function print 30 通常 data member 不放在 public 中, 而是放在 private 中 ,這樣才能隱藏 implementation , 這裡是為了示範讀 取方法起見,才寫 在 public 裡面。
74 31 cout << "Assign 10 to x and print using a pointer: "; 32 counterPtr->x = 10; // assign 10 to data member x 33 counterPtr->print(); // call member function print 34 return 0; 35} Assign 7 to x and print using the object's name: 7 Assign 8 to x and print using a reference: 8 Assign 10 to x and print using a pointer: 10
75 Separating Interface from Implementation Separating interface from implementation – 將原始程式分成幾個不同的檔案,比較容易管理。 –Makes it easier to modify programs –Header files Contains class definitions and function prototypes 實際上 data members 還是會放在 class 裡面, client 還 是會看到,有其他的方法可以將之對 client 端藏起來 (proxy class) 。 –Source-code files Contains member function definitions –Client files – 分成不同的檔案後,必須要將這些檔案編譯在一起。每個 compiler 編輯多個檔案的方法不同, Visual C++ 必須透過 project 的方式來將檔案編譯在一起,將要一起編譯的檔案 加到同一個 project 裡面去。
76 1// Fig. 6.5: time1.h 2// Declaration of the Time class. 3// Member functions are defined in time1.cpp 4 5// prevent multiple inclusions of header file 6#ifndef TIME1_H 7#define TIME1_H 8 9// Time abstract data type definition 10class Time { 11public: 12 Time(); // constructor 13 void setTime( int, int, int ); // set hour, minute, second 14 void printMilitary(); // print military time format 15 void printStandard(); // print standard time format 16private: 17 int hour; // int minute; // int second; // }; 21 22#endif If time1.h ( TIME1_H ) is not defined ( #ifndef ) then it is loaded ( #define TIME1_H ). If TIME1_H is already defined, then everything up to #endif is ignored. This prevents loading a header file multiple times. Dot (. ) replaced with underscore ( _ ) in file name.
77 23// Fig. 6.5: time1.cpp 24// Member function definitions for Time class. 25#include 26 27using std::cout; 28 29#include "time1.h" 30 31// Time constructor initializes each data member to zero. 32// Ensures all Time objects start in a consistent state. 33Time::Time() { hour = minute = second = 0; } 34 35// Set a new Time value using military time. Perform validity 36// checks on the data values. Set invalid values to zero. 37void Time::setTime( int h, int m, int s ) 38{ 39 hour = ( h >= 0 && h < 24 ) ? h : 0; 40 minute = ( m >= 0 && m < 60 ) ? m : 0; 41 second = ( s >= 0 && s < 60 ) ? s : 0; 42} 43 44// Print Time in military format 45void Time::printMilitary() 46{ 47 cout << ( hour < 10 ? "0" : "" ) << hour << ":" 48 << ( minute < 10 ? "0" : "" ) << minute; 49} 50 51// Print time in standard format 52void Time::printStandard() 53{ 54 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 ) 55 << ":" << ( minute < 10 ? "0" : "" ) << minute 56 << ":" << ( second < 10 ? "0" : "" ) << second 57 << ( hour < 12 ? " AM" : " PM" ); 58} Source file uses #include to load the header file Source file contains function definitions
78 // Fig. 6.5: fig06_05.cpp 、 client 端,要與 time1.cpp 一起編譯。 #include using std::cout; using std::endl; #include "time1.h" // Driver to test simple class Time int main(){ Time t; // instantiate object t of class time cout << "The initial military time is "; t.printMilitary(); cout << "\nThe initial standard time is "; t.printStandard(); t.setTime( 13, 27, 6 ); cout << "\n\nMilitary time after setTime is "; t.printMilitary(); cout << "\nStandard time after setTime is "; t.printStandard(); t.setTime( 99, 99, 99 ); // attempt invalid settings cout << "\n\nAfter attempting invalid settings:\n" << "Military time: "; t.printMilitary(); cout << "\nStandard time: "; t.printStandard(); cout << endl; return 0; } 執行結果與 fig06_03.cpp 相同。
79 Controlling Access to Members public –Presents clients with a view of the services the class provides (interface) –Data and member functions are accessible –A client of a class may be a member function of another class or it may be a global function. –struct 的內定 access 方式是 public ,也可以規定 public, private, 與 protected private –Default access mode –Data only accessible to member functions and friends –private members only accessible through the public class interface using public member functions
80 1// Fig. 6.6: fig06_06.cpp 2// Demonstrate errors resulting from attempts 3// to access private class members. 4#include 5 6using std::cout; 7 8#include "time1.h" 9 10int main() 11{ 12 Time t; // Error: 'Time::hour' is not accessible 15 t.hour = 7; // Error: 'Time::minute' is not accessible 18 cout << "minute = " << t.minute; return 0; 21} Compiling... Fig06_06.cpp D:\Fig06_06.cpp(15) : error C2248: 'hour' : cannot access private member declared in class 'Time' D:\Fig6_06\time1.h(18) : see declaration of 'hour' D:\Fig06_06.cpp(18) : error C2248: 'minute' : cannot access private member declared in class 'Time' D:\time1.h(19) : see declaration of 'minute' Error executing cl.exe. test.exe - 2 error(s), 0 warning(s) Attempt to access private member variable minute. Attempt to modify private member variable hour.
81 Access Functions and Utility Functions Utility functions –private functions that support the operation of public functions ,也就是放在 private 裡的涵 數。 –Not intended to be used directly by clients Access functions –public functions that read/display data or check conditions –Allow public functions to check private data , 也可以改變 private data 、呼叫 utility functions 。 Following example –Program to take in monthly sales and output the total –Implementation not shown, only access functions
82 87// Fig. 6.7: fig06_07.cpp 88// Demonstrating a utility function 89// Compile with salesp.cpp 90#include "salesp.h" 91 92int main() 93{ 94 SalesPerson s; // create SalesPerson object s s.getSalesFromUser(); // note simple sequential code 97 s.printAnnualSales(); // no control structures in main 98 return 0; 99} OUTPUT Enter sales amount for month 1: Enter sales amount for month 2: Enter sales amount for month 3: Enter sales amount for month 4: Enter sales amount for month 5: Enter sales amount for month 6: Enter sales amount for month 7: Enter sales amount for month 8: Enter sales amount for month 9: Enter sales amount for month 10: Enter sales amount for month 11: Enter sales amount for month 12: The total annual sales are: $ Create object s, an instance of class SalesPerson Use access functions to gather and print data ( getSalesFromUser and printAnnualSales ). Utility functions actually calculate the total sales, but the user is not aware of these function calls. Notice how simple main() is – there are no control structures, only function calls. This hides the implementation of the program.
83 // Fig. 6.7: salesp.h // SalesPerson class definition // Member functions defined in salesp.cpp #ifndef SALESP_H #define SALESP_H class SalesPerson { public: SalesPerson(); // constructor void getSalesFromUser(); // get sales figures from keyboard void setSales( int, double ); // User supplies one month's // sales figures. void printAnnualSales(); private: double totalAnnualSales(); // utility function double sales[ 12 ]; // 12 monthly sales figures }; #endif totalAnnualSales 放在 private ,只能在 class 裡面 使用, class 外面的程式碼不 能用。
84 // Fig. 6.7: salesp.cpp // Member functions for class SalesPerson #include using std::cout; using std::cin; using std::endl; #include using std::setprecision; using std::setiosflags; using std::ios; #include "salesp.h" // Constructor function initializes array SalesPerson::SalesPerson() { for ( int i = 0; i < 12; i++ ) sales[ i ] = 0.0; } // Function to get 12 sales figures from the user // at the keyboard void SalesPerson::getSalesFromUser() { double salesFigure; for ( int i = 1; i <= 12; i++ ) { cout << "Enter sales amount for month " << i << ": "; cin >> salesFigure; setSales( i, salesFigure ); }
85 // Function to set one of the 12 monthly sales figures. // Note that the month value must be from 0 to 11. void SalesPerson::setSales( int month, double amount ) { if ( month >= 1 && month 0 ) sales[ month - 1 ] = amount; // adjust for subscripts 0-11 else cout << "Invalid month or sales figure" << endl; } // Print the total annual sales void SalesPerson::printAnnualSales() { cout << setprecision( 2 ) << setiosflags( ios::fixed | ios::showpoint ) << "\nThe total annual sales are: $" << totalAnnualSales() << endl; } // Private utility function to total annual sales double SalesPerson::totalAnnualSales() { double total = 0.0; for ( int i = 0; i < 12; i++ ) total += sales[ i ]; return total; }
86 Initializing Class Objects: Constructors Constructors 的特性與功用 –Initialize class members –Same name as the class –No return type –Member variables can be initialized by the constructor or set afterwards – 宣告物件時自動被呼叫 –Class 被定義時,不能對 data member 作 initialize , 因為每個 object 的 data member 值不同,必須在宣 告 object 時才能透過 constructor 來作 initialized 。 – 類別中每個 data member 最好都有適當的 initialize 。
87 Using Default Arguments with Constructors Passing arguments to a constructor –When an object of a class is declared, initializers can be provided ,宣告物件時、在 物件名稱後面提供作 initialize 的參數。 –Format of declaration with initializers: Class-type ObjectName( value1,value2,…); –Default arguments may also be specified in the constructor prototype ;特別只在類別定義 中的 prototype 中作 default arguments 的宣告, 在 constructor 定義不要再作 default arguments 的宣告。
88 1// Fig. 6.8: time2.h 2// Declaration of the Time class. 3// Member functions are defined in time2.cpp 4 5// preprocessor directives that 6// prevent multiple inclusions of header file 7#ifndef TIME2_H 8#define TIME2_H 9 10// Time abstract data type definition 11class Time { 12public: 13 Time( int = 0, int = 0, int = 0 ); // default constructor 14 void setTime( int, int, int ); // set hour, minute, second 15 void printMilitary(); // print military time format 16 void printStandard(); // print standard time format 17private: 18 int hour; // int minute; // int second; // }; 22 23#endif Notice that default settings for the three member variables are set in constructor prototype. No names are needed; the defaults are applied in the order the member variables are declared.
89 23// Fig. 6.8: time2.cpp 24// Member function definitions for Time class. 25#include 26 27using std::cout; 28 29#include "time2.h" 30 31// Time constructor initializes each data member to zero. 32// Ensures all Time objects start in a consistent state // Set a new Time value using military time. Perform validity 36// checks on the data values. Set invalid values to zero. 37void Time::setTime( int h, int m, int s ) 38{ 39 hour = ( h >= 0 && h < 24 ) ? h : 0; 40 minute = ( m >= 0 && m < 60 ) ? m : 0; 41 second = ( s >= 0 && s < 60 ) ? s : 0; 42} 43 44// Print Time in military format 45void Time::printMilitary() 46{ 47 cout << ( hour < 10 ? "0" : "" ) << hour << ":" 48 << ( minute < 10 ? "0" : "" ) << minute; 49} 50 51// Print time in standard format 52void Time::printStandard() 53{ 54 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 ) 55 << ":" << ( minute < 10 ? "0" : "" ) << minute 56 << ":" << ( second < 10 ? "0" : "" ) << second 57 << ( hour < 12 ? " AM" : " PM" ); 58} 33 Time::Time(int hr, int min, int sec) { setTime(hr, min, sec); }
90 61// Fig. 6.8: fig06_08.cpp 62// Demonstrating a default constructor 63// function for class Time. 64#include 65 66using std::cout; 67using std::endl; 68 69#include "time2.h" 70 71int main() 72{ 73 Time t1, // all arguments defaulted 74 t2(2), // minute and second defaulted 75 t3(21, 34), // second defaulted 76 t4(12, 25, 42), // all values specified 77 t5(27, 74, 99); // all bad values specified cout << "Constructed with:\n" 80 << "all arguments defaulted:\n "; 81 t1.printMilitary(); 82 cout << "\n "; 83 t1.printStandard(); cout << "\nhour specified; minute and second defaulted:" 86 << "\n "; 87 t2.printMilitary(); 88 cout << "\n "; 89 t2.printStandard(); cout << "\nhour and minute specified; second defaulted:" 92 << "\n "; 93 t3.printMilitary(); Notice how objects are initialized: Constructor ObjectName ( value1,value2… ); If not enough values are specified, the rightmost values are set to their defaults.
91 OUTPUT Constructed with: all arguments defaulted: 00:00 12:00:00 AM hour specified; minute and second defaulted: 02:00 2:00:00 AM hour and minute specified; second defaulted: 21:34 9:34:00 PM hour, minute, and second specified: 12:25 12:25:42 PM all invalid values specified: 00:00 12:00:00 AM When only hour is specified, minute and second are set to their default values of cout << "\n "; 95 t3.printStandard(); cout << "\nhour, minute, and second specified:" 98 << "\n "; 99 t4.printMilitary(); 100 cout << "\n "; 101 t4.printStandard(); cout << "\nall invalid values specified:" 104 << "\n "; 105 t5.printMilitary(); 106 cout << "\n "; 107 t5.printStandard(); 108 cout << endl; return 0; 111}
92 Using Destructors Destructors –Are member function of class –Perform termination housekeeping before the system reclaims the object’s memory ,將物件所佔的記憶體歸還 給系統,實際的作法是將該記憶體設為可被使用的記憶體, 這樣如果系統有需要記憶體時,就可以使用。 – 在動態記憶體或動態資料結構的管理上很重要,第七、八 章會有比較多的例子 –Complement of the constructor –Name is tilde (~) followed by the class name (i.e., ~Time) Recall that the constructor’s name is the class name –Receives no parameters, returns no value –One destructor per class No overloading allowed – 作了前面幾項的話,都會產生 syntax error.
93 When Constructors and Destructors Are Called Constructors and destructors called automatically –Order depends on scope of objects Global scope objects –Constructors called before any other function (including main) –Destructors called when main terminates (or exit function called) –Destructors not called if program terminates with abort Automatic local objects –Constructors called when objects are defined ,當程式執行到宣 告此物件時,就執行該物件的 constructor 。 –Destructors called when objects leave scope( 順序通常與 constructor 相反 ) i.e., when the block in which they are defined is exited –Destructors not called if the program ends with exit or abort
94 When Constructors and Destructors Are Called Static local objects –Constructors called when execution reaches the point where the objects are defined( 與 automatic local object 一樣 ) –Destructors called when main terminates or the exit function is called( 順序與 constructor 相反,比 global 物件先作、比 automatic 物件 慢作 ) –Destructors not called if the program ends with abort
95 1// Fig. 6.9: create.h 2// Definition of class CreateAndDestroy. 3// Member functions defined in create.cpp. 4#ifndef CREATE_H 5#define CREATE_H 6 7class CreateAndDestroy { 8public: 9 CreateAndDestroy( int ); // constructor 10 ~CreateAndDestroy(); // destructor 11private: 12 int data; 13}; 14 15#endif
96 16// Fig. 6.9: create.cpp 17// Member function definitions for class CreateAndDestroy 18#include 19 20using std::cout; 21using std::endl; 22 23#include "create.h" 24 25CreateAndDestroy::CreateAndDestroy( int value ) 26{ 27 data = value; 28 cout << "Object " << data << " constructor"; 29} 30 31CreateAndDestroy::~CreateAndDestroy() 32 { cout << "Object " << data << " destructor " << endl; } Constructor and Destructor changed to print when they are called.
97 3. Create multiple objects of varying types 33// Fig. 6.9: fig06_09.cpp 34// Demonstrating the order in which constructors and 35// destructors are called. 36#include 37 38using std::cout; 39using std::endl; 40 41#include "create.h" 42 43void create( void ); // prototype 44 45CreateAndDestroy first( 1 ); // global object 46 47int main() 48{ 49 cout << " (global created before main)" << endl; CreateAndDestroy second( 2 ); // local object 52 cout << " (local automatic in main)" << endl; static CreateAndDestroy third( 3 ); // local object 55 cout << " (local static in main)" << endl; create(); // call function to create objects CreateAndDestroy fourth( 4 ); // local object 60 cout << " (local automatic in main)" << endl; 61 return 0; 62}
// Function to create objects 65void create( void ) 66{ 67 CreateAndDestroy fifth( 5 ); 68 cout << " (local automatic in create)" << endl; static CreateAndDestroy sixth( 6 ); 71 cout << " (local static in create)" << endl; CreateAndDestroy seventh( 7 ); 74 cout << " (local automatic in create)" << endl; 75} OUTPUT Object 1 constructor (global created before main) Object 2 constructor (local automatic in main) Object 3 constructor (local static in main) Object 5 constructor (local automatic in create) Object 6 constructor (local static in create) Object 7 constructor (local automatic in create) Object 7 destructor Object 5 destructor Object 4 constructor (local automatic in main) Object 4 destructor Object 2 destructor Object 6 destructor Object 3 destructor Object 1 destructor Notice how the order of the constructor and destructor call depends on the types of variables (automatic, global and static ) they are associated with. Program Output
99 Using Data Members and Member Functions Member functions –Allow clients of the class to set (i.e., write) or get (i.e., read) the values of private data members – 拿到 data member 值涵數名稱通常會有 get 的字眼;而設定某 data member 值的涵數則會加上 set 的字眼。 例如範例中 getHour(), setSecond(int) 等 –Providing set and get functions does not make private variables public 好處是:可以作合法性的測試;另一個很重要的好處是 data abstraction ,也就是就算資料的儲存方式改變了, 只要 member function 的原型不變, client 端的程式就不需改變 ( 可 能需要 recompile) 壞處很少,因為要呼叫涵數、因此速度稍微慢一點點 –A set function should ensure that the new value is valid – 實際執行 Fig6_10
100 A Subtle Trap: Returning a Reference to a Private Data Member Reference to an object –Alias for the name of the object –May be used on the left side of an assignment statement –Reference can receive a value, which changes the original object as well Returning references –public member functions can return non-const references to private data members Should be avoided, breaks encapsulation 會讓 client 的程式不需要透過 member function 就將資料存到 data member 的情形,如此可能破壞該資料的完整性。 如此也沒有達到 data hiding 的效果,如果 class 的資料表示方式 改了, client 程式很可能必須跟著改變。
101 1// Fig. 6.11: time4.h 2// Declaration of the Time class. 3// Member functions defined in time4.cpp 4 5// preprocessor directives that 6// prevent multiple inclusions of header file 7#ifndef TIME4_H 8#define TIME4_H 9 10class Time { 11public: 12 Time( int = 0, int = 0, int = 0 ); 13 void setTime( int, int, int ); 14 int getHour(); 15 int &badSetHour( int ); // DANGEROUS reference return 16private: 17 int hour; 18 int minute; 19 int second; 20}; 21 22#endif Notice how member function badSetHour returns a reference ( int & is the return type).
Load header 1.1 Function definitions 23// Fig. 6.11: time4.cpp 24// Member function definitions for Time class. 25#include "time4.h" 26 27// Constructor function to initialize private data. 28// Calls member function setTime to set variables. 29// Default values are 0 (see class definition). 30Time::Time( int hr, int min, int sec ) 31 { setTime( hr, min, sec ); } 32 33// Set the values of hour, minute, and second. 34void Time::setTime( int h, int m, int s ) 35{ 36 hour = ( h >= 0 && h < 24 ) ? h : 0; 37 minute = ( m >= 0 && m < 60 ) ? m : 0; 38 second = ( s >= 0 && s < 60 ) ? s : 0; 39} 40 41// Get the hour value 42int Time::getHour() { return hour; } 43 44// POOR PROGRAMMING PRACTICE: 45// Returning a reference to a private data member. 46int &Time::badSetHour( int hh ) 47{ 48 hour = ( hh >= 0 && hh < 24 ) ? hh : 0; return hour; // DANGEROUS reference return 51} badSetHour returns a reference to the private member variable hour. Changing this reference will alter hour as well. 雖然這個地方有檢查 hh 是否超過 0~23 的範圍,但是 client 可以透過 reference 的方式跳過它的檢查
Declare reference 2. Change data using a reference 3. Output results 52// Fig. 6.11: fig06_11.cpp 53// Demonstrating a public member function that 54// returns a reference to a private data member. 55// Time class has been trimmed for this example. 56#include 57 58using std::cout; 59using std::endl; 60 61#include "time4.h" 62 63int main() 64{ 65 Time t; 66 int &hourRef = t.badSetHour( 20 ); cout << "Hour before modification: " << hourRef; 69 hourRef = 30; // modification with invalid value 70 cout << "\nHour after modification: " << t.getHour(); // Dangerous: Function call that returns 73 // a reference can be used as an lvalue! 74 t.badSetHour(12) = 74; 75 cout << "\n\n*********************************\n" 76 << "POOR PROGRAMMING PRACTICE!!!!!!!!\n" 77 << "badSetHour as an lvalue, Hour: " 78 << t.getHour() 79 << "\n*********************************" << endl; return 0; 82} Declare Time object t and reference hourRef that is assigned the reference returned by the call t.badSetHour(20). 透過 reference 變數的設定, 就可以將錯誤的資料寫到 private data member 中 badSetHour 回傳值的型態是 reference ,可當作記憶體位置 來看,可以存錯誤的資料進去。 Hour before modification: 20 Hour after modification: 30 ********************************* POOR PROGRAMMING PRACTICE!!!!!!!! badSetHour as an lvalue, Hour: 74 *********************************
104 Program Output HourRef used to change hour to an invalid value. Normally, the function setbadSetHour would not have allowed this. However, because it returned a reference, hour was changed directly. 所以寫程式時,儘量避免 member function 的傳回值是指 向 private data member 的 reference 。 Hour before modification: 20 Hour after modification: 30 ********************************* POOR PROGRAMMING PRACTICE!!!!!!!! badSetHour as an lvalue, Hour: 74 *********************************
105 Assignment by Default Memberwise Copy Assigning objects –An object can be assigned to another object of the same type using the assignment operator (=) –Member by member copy – 將物件中每個成員都複製到另一個物件中的成員。 Objects may be –Passed as function arguments –Returned from functions (call-by-value default) – 將物件當參數或傳回值型態時,也是用前面的 assign 方式。 Call-be-value 比較安全、速度慢; call-by-reference 速度 較快、較不安全; call-by-const-reference 可達到速度快 又安全的效果。
106 1// Fig. 6.12: fig06_12.cpp 2// Demonstrating that class objects can be assigned 3// to each other using default memberwise copy 4#include 5 6using std::cout; 7using std::endl; 8 9// Simple Date class 10class Date { 11public: 12 Date( int = 1, int = 1, int = 1990 ); // default constructor 13 void print(); 14private: 15 int month; 16 int day; 17 int year; 18}; 19 20// Simple Date constructor with no range checking 21Date::Date( int m, int d, int y ) 22{ 23 month = m; 24 day = d; 25 year = y; 26} 27 28// Print the Date in the form mm-dd-yyyy 29void Date::print() 30 { cout << month << '-' << day << '-' << year; }
int main() 33{ 34 Date date1( 7, 4, 1993 ), date2; // d2 defaults to 1/1/ cout << "date1 = "; 37 date1.print(); 38 cout << "\ndate2 = "; 39 date2.print(); date2 = date1; // assignment by default memberwise copy 42 cout << "\n\nAfter default memberwise copy, date2 = "; 43 date2.print(); 44 cout << endl; return 0; 47} date1 = date2 = After default memberwise copy, date2 = date2 set equal to date1, and all member variables are copied.
108 Software Reusability Software resusability –Implementation of useful classes –Class libraries exist to promote reusability Allows for construction of programs from existing, well-defined, carefully tested, well-documented, portable, widely available components –Speeds development of powerful, high-quality software – 如何知道現存的 class 符合我的需要呢?