CLASSES AND DATA ABSTRACTION In this chapter, you will: Learn about classes Learn about private, protected, and public members of a class Explore how classes are implemented Examine constructors and destructors Learn about the abstract data type (ADT) Explore how classes are used to implement ADT Learn about information hiding Explore how information hiding is implemented in C++ CLASSES A class is a collection of a fixed number of components, called members of the class. A member of a class can either be a variable (that is, to store some data) or a function. The general syntax of declaring a class is: class classIdentifier { classMemberList }; A member function can (directly) access any member of the class— data members and function members. In C++, class is a reserved word and it only defines a data type, no memory is allocated. The semicolon after the right brace is part of the syntax. The members of a class are classified into three categories: private, public, and protected. By default, all members of a class are private. If a member of a class is private, you cannot access it outside the class. A public member is accessible outside the class. To make a member of a class public, you use the label public with a colon. Declare a class, ClockType, to implement the time of day in a program. Time is represented as a set of three integers: one to represent the hours, one to represent the minutes, and one to represent the seconds. Perform the following operations on the time: 1. Set the time. 2. Return the time. 3. Increment the time by one second. 4. Increment the time by one minute. 5. Increment the time by one hour. 6. Compare the two times for equality. #include <iostream> using namespace std; class ClockType { public: void setTime(int, int, int); void getTime(int& hours, int& minutes, int& seconds); void void void bool incrementSeconds(); incrementMinutes(); incrementHours(); equalTime(const ClockType& otherTime) const; private: int hr; int min; int sec; }; The class ClockType has three data members: hr, min, and sec, they are private to the class and cannot be accessed outside the class. It has seven function members: setTime, getTime, printTime, incrementSeconds, incrementMinutes, incrementHours, and equalTime —which can directly access the data members (hr, min, and sec). In the function equalTime, the parameter otherTime is a constant reference parameter. That is, otherTime cannot modify the value of the actual parameter. The word const at the end of the member function equalTime specifies that these functions cannot modify the data members of a variable of the type ClockType. Declare Object Variable (Use class) Once a class is declared, you can declare variables of that type. In C++ terminology, a class variable is called an object or class instance. The syntax for declaring a class object is the same as that for declaring any other variable. ClockType myClock; ClockType yourClock; Accessing Class Members Once an object is declared, it can access the public members of a class. The general syntax to access the member of a class is classVariableName.memberName In C++, the dot, . (period), is an operator called the member access operator. Example myClock.setTime(5,2,30); yourClock.setTime(x,y,z); //Assume x, y, and //z are variables of the type int if(myClock.equalTime(yourClock)) . . . myClock.hr = 10; myClock.min = yourClock.min; //illegal //illegal Built-in Operations on Classes Most of C++’s built-in operations do not apply to classes. You cannot use arithmetic operators to perform arithmetic operations on class objects (unless they are overloaded). For example, you cannot use the operator + to add two class objects of, say, the type ClockType. Also, you cannot use relational operators to compare two class objects for equality. The two built-in operations that are valid for class objects are member access (.) and assignment (=). The Assignment Operator and Classes • Suppose that myClock and yourClock are variables of the type ClockType. The statement myClock = yourClock; copies the value of yourClock into myClock • the value of yourClock.hr is copied into myClock.hr, • the value of yourClock.min is copied into myClock.min • the value of yourClock.sec is copied into myClock.sec Functions and Objects Objects can be passed as parameters to functions and returned as function values. Objects can be passed either by value or by reference. If an object is passed by value, the contents of the data members of the actual parameter are copied into the corresponding data members of the formal parameter. This operation might require, in addition to a large amount of storage space, a considerable amount of computer time to copy the value of the actual parameter into the formal parameter. Reference Parameters and Object Variables If a variable is passed by reference, the formal parameter receives only the address of the actual parameter. Therefore, an efficient way to pass a variable as a parameter is by reference. If a variable is passed by reference, then when the formal parameter changes, the actual parameter also changes. In C++, you can pass a variable by reference and still prevent the function from changing its value, by using the keyword const in the formal parameter declaration. void testTime(const ClockType& otherClock) { ClockType dClock; ... } Implementation of Member Functions (Definition) • In the heading of the function definition, the name of the function is the name of the class followed by the scope resolution operator followed by the function name. void ClockType::setTime(int hours, int minutes, int seconds) { if(0 <= hours && hours < 24) hr = hours; else hr = 0; if(0 <= minutes && minutes < 60) min = minutes; else min = 0; if(0 <= seconds && seconds < 60) sec = seconds; else sec = 0; } myClock.setTime(3,48,52); //call void ClockType::getTime(int& hours, int& minutes, int& seconds) { hours = hr; minutes = min; seconds = sec; } void ClockType::incrementHours() { hr++; if(hr > 23) hr = 0; } void ClockType::incrementMinutes() { min++; if(min > 59) { min = 0; incrementHours(); } } void ClockType::incrementSeconds() { sec++; if(sec > 59) { sec = 0; incrementMinutes(); } } bool ClockType::equalTime(const ClockType& otherClock) const { return (hr == otherClock.hr && min == otherClock.min && sec == otherClock.sec); } Suppose that if(myClock.equalTime(yourClock)) . . . //Program that uses the class ClockType int main() { ClockType myClock; ClockType yourClock; int hours; int minutes; int seconds; myClock.setTime(5,4,30); printTime(myClock); printTime(yourClock); yourClock.setTime(5,45,16); cout<<"After setting - yourClock: "; printTime(yourClock); if(myClock.equalTime(yourClock)) cout<<"Both times are equal."<<endl; else cout<<"Both times are not equal."<<endl; cout<<"Enter hours, minutes, and seconds: "; cin>>hours>>minutes>>seconds; myClock.setTime(hours,minutes,seconds); cout<<"New myClock: "; printTime(myClock); myClock.incrementSeconds(); cout<<"After incrementing the clock by " <<"one second, myClock: "; printTime(myClock); return 0; }//end main Output: The user input is in red. myClock: 05:04:30 yourClock: (The value of yourClock is undefined here). After setting - yourClock: 05:45:16 The two times are not equal Enter hours, minutes, and seconds: 5 23 59 New myClock: 05:23:59 After incrementing the time by one second, myClock: 05:24:00 Constructors and Destructors Constructors We can guarantee the initialization of the data members of a class by using constructors. • There are two types of constructors: with parameters and without parameters. • The constructor without parameters is called the default constructor. 1. The name of a constructor is the same as the name of the class. 2. A constructor, even though it is a function, has no type. That is, it is neither a value-returning function nor a void function. 3. A class can have more than one constructor. However, all constructors of a class have the same name. 4. If a class has more than one constructor, they must have different sets of parameters. 5. Constructors are automatically executed when an instance of the class is declared. Since they have no types, they are not called like other functions. 6. Which constructor executes depends on the type of values passed to the class variable when the class variable is declared. class ClockType { public: void setTime(int, int, int); void getTime(int&, int&, int&); void incrementSeconds(); void incrementMinutes(); void incrementHours(); bool equalTime(const ClockType&) const; ClockType(int, int, int); //constructor with parameters ClockType(); //default constructor private: int hr; int min; int sec; }; ClockType::ClockType(int hours, int minutes, int seconds) { if(0 <= hours && hours < 24) hr = hours; else hr = 0; if(0 <= minutes && minutes < 60) min = minutes; else min = 0; if(0 <= seconds && seconds < 60) sec = seconds; else sec = 0; } ClockType::ClockType() { hr = 0; min = 0; sec = 0; } //default constructor Invoking a Constructor •A constructor is automatically executed when an object is declared. Invoking the default Constructor The syntax to invoke the default constructor is: className classVariableName; Example: ClockType yourClock; In this case, the default constructor is executed and the data members of yourClock will be initialized to zero. Invoking a Constructor with Parameters The syntax to invoke a constructor with parameter is: className classVariableName(argument1, argument2,. . . ); where argument1, argument2, etc. is either a variable or an expression. 1. The number of arguments and their type should match with the formal parameters (in the order given) of one of the constructors. 2. If the type of the arguments do not match with the formal parameters of any constructor (in the order given), C++ will use type conversion and look for the best match. For example, an integer value might be converted to a floating-point value with zero decimal part. An ambiguity will result in a compile time error. Consider the statement. ClockType myClock(5,12,40); This statement declares a class variable myClock. • In this case, the constructor with parameters of the class ClockType will be executed and the three data members of the variable myClock will be set to 5, 12, and 40. Arrays of Objects and Constructors If a class has constructors and you declare an array of objects, the class must have the default constructor. The default constructor is used to initialize each (array) class object. ClockType clocks[100]; Destructors Like constructors, destructors are also functions. The name of a destructor is the character '~' followed by the name of the class. The name of the destructor for the class ClockType is ~ClockType(); A class can have only one destructor and it has no parameters. The destructor is automatically executed when the class object goes out of scope. Data Abstraction, Classes, and Abstract Data Types Abstract Data Type (ADT: A data type that specifies the logical properties without the implementation details. An ADT has three things associated with it. The name of the ADT, called type name. The set of values belonging to the ADT, called domain. The set of operations on the data. dataTypeName ClockType domain Each ClockType value is a time of day in the form of hours, minutes, and seconds. operations Set the time. Return the time. Increment the time by one second. Increment the time by one minute. Increment the time by one hour. Compare the two times to see whether they are equal. Example 13-8 A list is defined as a set of values of the same type. All values in a list are of the same type; a convenient way to represent and process a list is to use an array. You can define a list as an ADT as follows: dataTypeName ListType domain Every element of the type ListType is a set of, say 1000 numbers. operations Check to see if the list is empty. Check to see if the list is full. Search the list for a given item. Delete an item from the list. Insert an item in the list. Sort the list. Destroy the list. • The following class defines the list ADT. class ListType { public: bool isEmptyList(); bool isFullList(); void search(int searchItem, int& found); void insert(int newElement); void remove(int removeElement); void destroy(); ListType(); //constructor private: int list[1000]; int length; }; INFORMATION HIDING Implementation file. Header file (Specification file). The header file has an extension h. The implementation file has an extension cpp. The implementation file must include the header file via the include statement. In a include statement, user defined header files are enclosed in double quotes while system provided header files are enclosed between angular brackets. //clock.h, the specification file for the class ClockType class ClockType { public: void setTime(int hours, int minutes, int seconds); //Purpose: To set the time according to the //parameters: hr = hours; min = minutes; // sec = seconds //Receives: hours, minutes, seconds (ints) //Returns: None void getTime(int& hours, int& minutes, int& seconds) //Purpose: to return the time through parameters: // hours = hr; minutes = min; seconds = sec //Receives: None //Returns: hours, minutes, seconds (ints) void incrementSeconds(); //Purpose: to increment the time by one second //If the before-increment time is 23:59:59, the time //is reset to 00:00:00 //Receives: None //Returns: None void incrementMinutes(); //Purpose: to increment the time by one minute //If the before-increment time is 23:59:53, the time //is reset to 00:00:53 //Receives, Returns: None void incrementHours(); //Purpose: to increment the time by one hour //If the before-increment time is 23:45:53, the time //is reset to 00:45:53 //Receives, Returns: None bool equalTime(const ClockType& otherClock) const; //Purpose: to compare the two times //Receives: otherClock (ClockType) //Returns: true if this time is equal to //otherTime, otherwise returns false ClockType(int hours, int minutes, int seconds); //Purpose: To construct time and initialize it //according to the parameters // hr = hours; min = minutes; sec = seconds //Receives: hours, minutes, seconds (ints) //Returns: NONE ClockType( ); //Purpose: To construct time and initialize it // hr = 0; min = 0; sec = 0 //Receives: Nonr //Returns: NONE private: int hr; //store hours int min; //store minutes int sec; //store seconds }; //clockImp.cpp, the implementation file #include <iostream> #include "clock.h" using namespace std; . . . //The definition of the member functions of the ClockType //goes here. . . . //TestClock.cpp. //ClockType The user program that uses the class #include <iostream> #include "clock.h" using namespace std; . . . //Place the definitions of the function main and the other //user-defined functions here . . . EXECUTABLE CODE To use the class ClockType, the program must include the header file clock.h via the include statement. //Program File: test.cpp #include "clock.h" . . . int main() { . . . } The program test.cpp must include only the header file, not the implementation file. To create the executable code to run the program test.cpp, the following steps are required: Microsoft Visual Cput the editor, compiler, and linker all into one package. With one command, the program is compiled and linked with the other necessary files. These systems also manage multiple file programs in the form of a project. A project consists of several files, called the project files. These systems usually have a command, called build (or make). When the build command is applied to a project, the system automatically compiles and links all files required to create the executable code. When one or more files in the project change, you can use these commands to recompile and relink the files. OO terms • • • • • class object instance variables (member data) methods (member functions) sending message (call to a member function) Three important characteristics of OOP • 1. Encapsulation - see Section 2.1 • 2. Inheritance - hierarchy in which descendant class inherits data and operations from ancestor class furniture • Example: chable table End table ottoman chair dinette OO terms • 3. Polymorphism - several operations with same name – binding time - time name/symbol bound to code/value – static binding - resolved at compiled time – dynamic binding - resolved at run time – operation overloading - static binding