<<

Abstract Types

Representing information is fundamental to science. The primary purpose of most computer programs is not to perform calculations, but to store and efficiently retrieve information. For this reason, the study of data and the that manipulate them is at the heart of .

Different Views of Data:

-When we talk about the of a program we use the words “add”, “read”, “calculate”. The function of a program describes what it does in terms of the verbs or actions. The data are the nouns of the programming world: the objects that are manipulated, the information that is processed by the . view all information as of 0s and 1s, however as humans we tend to think in larger units such as numbers, lists, etc.. We use what is called Data abstraction

Data Abstraction: We use data abstraction, even when we think we are manipulating concrete entities: For example, our program might be using , however the physical representation of an might differ from one machine to the other. The way that integers are physically represented determines how the computer manipulates them. However as programmers, we rarely get involved at this level.

Binary : 10011001 : 153 (unsigned), -25 (sign and magnitude) -102 (one’s complement), -103 (two’s complement)…

Data Encapsulation:

Data encapsulation means that the physical representation of a program’s data is surrounded. The user of the data does not see, nor usually cares about the , but deals with the data only in its logical picture- its abstraction. To make encapsulation effective, operations must be provided to allow the user to create, access and change data. For example for the int, ++ provides ways to create variables of this data type by using declarations; we can assign values to them using the assignment operator, we can perform arithmetic operations using +, - *,….

Abstract Data Type and Data structures: A type is a collection of values. For example the Boolean type consists of the values true and false. The integers also form a type. An integer is a simple type because its values contain no subparts. A bank account record will typically contain several pieces of information such as name, address, account number, and an account balance. Such a record is an example of an aggregate type or composite type. A data type is a type together with a collection of operations to manipulate the type.

An (ADT)

A data type whose properties are specified independently of any particular implementation. An abstract data type describes the logical properties of the data type. The of the ADT is defined in terms of a type and a of operations on that type. The behavior of each operation is determined by its inputs and outputs. An ADT does not specify how the data type is implemented, these details are hidden from the user of the ADT and protected from outside access by encapsulation..

Data encapsulation: The separation of the representation of data from the applications that use the data at a logical level. A data is the concrete implementation of an ADT. Data structures are usually aggregate types; they can be decomposed into their elements. The arrangement of these components is a feature of the structure that effects how each element can be accessed. Both the arrangement of the elements and the way they are accessed can be encapsulated.

Example: a A library can be decomposed into its component elements : books. The collection of individual books can be arranged in a number of ways. However the user need not know the system in order to locate a book, because the librarian or the directory can point him/her to the book they want.

We use the same approach to data structures: A is defined by 1) the logical arrangement of data elements combined with (2) the set of operations we need to access the elements.

Abstract Data Types Operator Categories: Four operations are performed on an abstract data type: constructors, transformers, observers, and iterators.

A constructor is an operation that creates a new instance (object) of an ADT. It is invoked at the language level by some sort of declaration.

Transformers are operations that change the state of one or more of the data values, such as inserting an item into an object, deleting an item from an object… An observer is an operation that allows us to observe the state of one or more of the data values without changing them. These include predicates checking if a certain property is true, accessor or selector functions that return a copy of an item …

An iterator is an operation that allow us to process all components in a data structure sequentially.

Composite Data Types C++ provides three types of composite data types: records (struct), classes and arrays with various dimensions. Classes and structs can have member functions as well as data. Classes and structs are logically unstructured.

Records: In C++, records are implemented by structs. C++ classes are another implementation of a record.

Logical Level: A record is a composite type made up of a finite collection of not necessarily homogeneous elements called members or fields. Accessing is done directly through a set of named member or field selectors. struct CarType { int year; char maker[10]; float price; }; CarType myCar;

The record variable myCar is made up of 3 components. The first, year is of type int. The second, maker, is an array of characters. The third, price, is a float number. The name of the components make up the set of member selectors. The syntax of the component selector is the record variable name, followed by a period, followed by member selector. myCar.price

Higher-Level Abstraction and the C++ Class Type When we design an ADT, we want to bind the operations of the data type with the data that are being manipulated. The Class Type is the perfect mechanism for doing that. The class type is a construct in which the members of the class can be both functions and data. A class encapsulates a fixed number of data components with the functions that manipulate them; the predefined operations on an instance of a class are whole assignment and component access.

In an object-oriented language, such as C++, an ADT and its implementation together make up a class. Each operation associated with the ADT is implemented by a member function. The variables that define the space required by a data item are referred to as data members. An object is an instance of a class, that is, something that is created and takes up storage during the execution of a computer program. Classes are written in two parts, the specification and the implementation. The specifications include data and operations on the data. The implementation section fully defines the operations and provides the manner in which these data can be manipulated.

Class Specification:

Although the class specification and implementation could reside in the same file, the two parts of a class are usually separated into two files. The specification goes into a header file(.h extension) and the implementation goes into a file with the same name but with a .cpp extension.

//Declares a class to represent the Date ADT. //This is file DateType.h class DateType { public: void Initialize(int newMonth, int newDay, int newYear); int GetYear() const; int GetMonth() const; int GetDay() const; private: int year; int month; int day; };

The member functions of the class are Initialize, GetYear, GetMonth, GetDay. They are marked public, which means that outside code (client) can access these functions. Initialize is a constructor operation: it takes values for the year, month and day and stores these values into the appropriate data members of an instance of the class or an object. GetYear, GetMonth and GetDay are accessor functions, they access data members of the class. The const beside accessor function names guarantees that these functions do not change any of the data members of the objects to which they apply.

Class Implementation Only member functions of the class DateType can access the data members. so we must associate the class name with the function definitions. We do so by inserting the class name before the function name, separated by the resolution operator(::)

The implementation of the member functions goes into the file DateType.cpp. To access the specifications, we must insert the file DateType.h by using an #

//Define member functions of class DateType //This is the file DateType.cpp #include “DateType.h” //Gain access to the specification of the class void DateType::Initialize (int newMonth, int newDay, int newYear) { year= newYear; month= newMonth; day= newDay; } int DateType::GetMonth() const { return month; } int DateType::GetDay() const { return day; } int DateType::GetYear() const { return year; }

A client of the class DateType must have an #include “DateType.h” directive for the specification (header) file of the class. Note: System-supplied header files are enclosed in angle- brackets, whereas user defined header files are enclosed in double quotes. The client then declares a variable of type DateType just as it would any other variable. #include #include “DateType.h” using namespace std; DateType today; DateType anotherDay; today. Initialize(9, 5, 2007); anotherDay.Initialize(9, 25, 2007); cout << “ Today is “<

Member functions with Object Parameters A member function applied to a class object uses the dot . If we want a member function to operate on more than one object- for example a function that compares the data members of two instances of the class, then an object has to be passed as an argument to the function. Example: Let’s expand our class DateType with a member function ComparedTo that compares two date objects: the instance to which it is applied and its parameter. The function returns LESS if the instance comes before the parameter, EQUAL if they are the same and GREATER if the instance comes after the parameter. We will define an containing these constants: enum RelationType{LESS, EQUAL, GREATER} //Prototype of member function in the specification file

RelationType ComparedTo(DateType someDate); //Compares self with someDate

To determine which date comes first, we must compare the year members of the instance and the parameter. If they are the same, we must compare the month members. If the year members and the month members are the same, we must compare the day members. To access the fields of the instance, we just use their names. To access the fields of the parameter, we prefix the field name with the parameter name and a dot.

RelationType DateType::ComparedTo(DateType aDate)

{ if (year aDate.year) return GREATER; else if (month aDate.month) return GREATER; else if (day < aDate.day) return LESS; else if (day >aDate.day) return GREATER else return EQUAL; }

In this code, the year refers to the year data member of the object to which the function is applied; aDate.year refers to the data member of the object passed as a parameter. The object to which the a member function is applied is called self. In the function definition, the data members of self are referenced directly without using the dot notation. switch (today.ComparedTo(anotherDay)) { case LESS : cout << “today comes before anotherDay”; break; case GREATER : cout <<”Today comes after anotherDay”; break; case EQUAL : cout << ” Today and anotherDay are the same”; break; }