1 Data Structures and Algorithms Week 3 Data Abstraction Part I: Modules and Information Hiding.

Post on 13-Dec-2015

216 views 0 download

Tags:

transcript

1

Data Structures and Algorithms

Week 3Data Abstraction Part I:

Modules and Information Hiding

2

A Module

• The use of modularization is part of the process of decomposing a single, large program.

• Modularization happens naturally when using stepwise refinement

• A function is a type of modularity. It is a collection of instructions and local data, all contributing to achieve the purpose of the function

• A module is a collection of related items (functions, types, constants, and variables) packed into a separate compiled unit

• It is organized so that programs and other functions can use all or part of the module

3

Modules

• A module normally has two parts:– The public view: It consists of the client programs can see

from the module. It is sometimes called the interface.– The private view: Consists of the internal implementation

of the functions and auxiliary functions that are used by the main ones

• The goal when using modules is to encapsulate the internals of the functions and private data.

• Encapsulation is the bundling together of all the information, capabilities, and responsibilities of an entity into a single unit

• Encapsulation ensure that clients do not depend on implementation details

4

Advantages of Separate Compilation of Modules

• Modularization is only achievable if the language allows separate compilation

• RE-USE: One module may be used by many clients.

• EASE OF MODIFICATION: – Modules can be recompiled without recompiling the

whole system– Conversely, clients can be modified and the modules do

not need to be recompiled.

• CONFIDENTIALITY: The module’s .cpp file may be removed and just its .obj code is left.

5

Program with several modules

module1.h module2.h module3.h

mainprog.cpp module1.cpp module2.cpp module3.cpp

COMPILER COMPILER COMPILER COMPILER

6

Object files are linked to form one executable file

mainprog.obj module1.obj module2.obj module3.obj

LINKER

mainprog.exe

7

Modules in C++

• A module is represented by two files– <file>.h: This file is a C++ header file. It contains only

declarations. Sometimes called the specification file– <file>.cpp: This file contains the executable instructions (the

implementation of the header defined in the .h file) and date. Normally called implementation file

• The specification file is inserted into some other file via the #include directive. – It has to be included in the client and the module implementation

file– Should be included using "filename.h" instead of <filename.h>

8

Specification file ( .h) contains

preprocessor directives #include “bool.h”#ifndef RAND_H

constant declarations const float PI = 3.14159;const int TRUE = 1;

type declarations typedef int Boolean;typedef char String20[21];typedef String20 Names[100];

function prototypes with formal parameters includingcomments /* in */, /* out */, /* inout */,and PRE and POST assertions

9

Specification file ( .h) does not contain

• What should not appear in a specification file– Functions with bodies– Variable definitions

10

Modules use 2 separate files

// SPECIFICATION FILE ( power.h ) // // Specifies this module’s constants, types, // and functions.

. . .

// IMPLEMENTATION FILE ( power.cpp ) // // Implements this module’s functions.

#include “power.h”

. . .

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // SPECIFICATION FILE ( power.h ) // This module provides exponentiation functions // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

int power( /* in */ int someInt, /* in */ int exp ); //------------------------------------------------------------------------------------

// PRE: Assigned(someInt) && exp >= 0 // POST: FCTVAL == someInt raised to the power "exp" // (NOTE: Large exponents may produce overflow)

//------------------------------------------------------------------------------------

float power( /* in */ float someFloat, /* in */ int exp );//------------------------------------------------------------------------------------// PRE: Assigned(someFloat) && Assigned(exp)// && (exp < 0) --> someFloat != 0.0// POST: FCTVAL == someFloat raised to the power "exp"// (NOTE: Large exponents may produce overflow)//------------------------------------------------------------------------------------

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // IMPLEMENTATION FILE ( power.cpp ) // This module provides exponentiation functions.

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#include “ power.h” // also must appear in client code int power( /* in */ int someInt, /* in */ int exp ) {

//------------------------------------------------------------------------------------ // PRE: Assigned(someInt) && exp >= 0

// POST: FCTVAL == someInt raised to the power "exp"// (NOTE: Large exponents may produce overflow)//------------------------------------------------------------------------------------

int i; int partialVal = 1; for (i = 1; i <= exp; i++)

//----------------------------------------------------------------------------------- // INV (prior to test): // partialVal == someInt raised to power (i-1) // && i <= exp+1

//------------------------------------------------------------------------------------ partialVal *= someInt; return partialVal;}

//------------------------------------------------------------------------------------// PRE: Assigned(someFloat) && Assigned(exp) && (exp < 0) --> someFloat != 0.0// POST: FCTVAL == someFloat raised to the power "exp"// (NOTE: Large exponents may produce overflow)//------------------------------------------------------------------------------------float power( /* in */ float someFloat, /* in */ int exp ) { if(exp < 0) { // Negative exponent means someFloat = (float)1.0/someFloat; // repeated division exp = -exp; } int i; float partialVal = 1.0; for (i = 1; i <= exp; i++)

//------------------------------------------------------------------------------------// INV (prior to test):

// partialVal == someFloat<entry> raised to power (i-1) // && i <= abs(exp<entry>)+1

//------------------------------------------------------------------------------------ partialVal *= someFloat; return partialVal;}

14

Using the Power Module

//----------------------------------------------------------------------// powsof2.cpp// This program outputs the powers of 2 from 1 through 10.// NOTE: 2^n denotes 2 raised to the nth power//----------------------------------------------------------------------#include <iostream.h>#include <iomanip.h> // For setw()#include "powers.h" // For PowerOfInt()

int main(){ int power;

cout << " Power 2 ^ Power \n" << " ----- --------- \n";

for (power = 1; power <= 10; power++) // INV (prior to test): // 2^1, 2^2, ..., 2^(power-1) have been output // && power <= 11 cout << setw(10) << power << setw(13) << PowerOfInt(2, power) << '\n';

return 0;}

15

Information Hiding

• A consequence of using modules in C++• The use of specification files (.h) and implementation

files improves the concept of black boxes.• The black box idea is called in the OO world information

hiding• The advantages of such an idea has been discussed in our

previous classes – Software reuse– Improved communication among the developers

• To improve information hiding avoid global variables and use the static keyword only when necessary

16

A Case StudyA Password Module

• The purpose is to manage password access• We'll try to use the main concepts discussed thus

far.– Use of internal documentation– Use of modules

• Specification file

• Implementation file

– Extending the language. Providing features for password as if it were a built in facility

– Using information hiding

17

Specification FilePassword.h

#include "bool.h" // Defined later

// PRE: Input is coming from the keyboard// POST: After a prompt, the user has supplied a passwordvoid getPassword();

// PRE: getPassword has been invoked previously &&// Input is coming from the keyboard// POST: The user has been prompted to repeat the most// recently supplied password && // FCTVAL == TRUE, if the passwords are identical// == FALSE, otherwiseBoolean validUser();

18

Implementation FilePassword.cpp

#include "bool.h" // Defined later#include "password.h" // Specification file#include <iostream>using std::cin;using std::cout;const int MAXLEN = 10; // Max password lengthstatic char passStr[MAXLEN+1]; // Updated as a global variable// PRE: Input is coming from the keyboard// POST: The user has typed a password which is, say,// "len" characters long (up to '\n')// && (len <= MAXLEN ) --> (passStr[0..len-1] == input string// && passStr[len] == '\0')&& (len > MAXLEN ) --> (passStr[0..MAXLEN-1]// == start of input string&& passStr[MAXLEN] == '\0')void getPassword(){ cout << "Type password then <RETURN> (Max: " << MAXLEN << " --> "; cin.get(passStr, MAXLEN+1); cin.ignore(100, '\n'); // Previous "get" doesn't consume '\n'}

// PRE: passStr contains a string terminated by '\0'&& Input is coming from the// keyboard// POST: A user-input sequence of chars (thru '\n') has been read// && FCTVAL == TRUE, if the input chars up to '\n' equal the chars of // // passStr up to '\0'. FALSE, otherwise

Boolean validUser() { char inChar; int i = 0; cout << "Type password then <RETURN> --> "; cin.get(inChar); while (inChar == passStr[i]) { // INV All passStr[0..i-1] match input i++; cin.get(inChar); } // ASSERT: inChar != passStr[i] if (inChar == '\n') // ASSERT: Input password may be valid return (passStr[i] == '\0'); else { // ASSERT: Input password definitely invalid cin.ignore(100, '\n'); // Consume chars through '\n' return FALSE; }

Implementation File Password.cpp

20

Test File (Bottom-Up Test)TestPass.cpp

#include "password.h"#include <iostream>using std::cout;

int main() { getPassword(); // ASSERT: User has entered an initial password cout << "Please verify the password:\n"; if ( !validUser() ) { cout << "Verification failed!\n"; return 1; } return 0;}

21

Specification file ( .h) purpose

It is public interface of the module.

It lists the module items that a client can use.

We say the module exports these items.

22

Implementation ( .cpp) file

Must contain a function definition (both heading and body) for each function declared in the .h file of the module.

It is considered the black box of the module which hides information details that the client does not need to know.

23

C++ Standard Library

• C++ is small• Most of the functions are not part of the language• Most of C++ environments follow some standard

(ANSI/ISO) in what functions the provide.• C++ has a set of specification files, but the

implementations are put together into Libraries (.lib files)

24

C++ Standard Library

• The most common specification files are:– iostream.h: Contains functions prototypes for the

standard input and standard output functions. The header file for this is <iostream>

– math.h: Contains function prototypes for math library functions. The header file is <cmath>

– ctype.h: Contains function prototypes for functions that test characters for certain properties and for functions that can be used to convert lowercase letters to uppercase and vice versa. The header file is <cctype>

– string.h: Contains functions prototypes for string processing functions. The header file is <cstring>

25

C++ Standard Library

• Some other specification files:– assert.h: Contains macros and information for adding

diagnostics that aid debugging. The header file is <cassert>

– time.h: Contains function prototypes for manipulating date and time. The header file is <ctime>

– stdlib.h: Contains function prototypes for conversion of numbers to text, text to numbers and other utility functions. The header file is <cstdlib>

– fstream.h: Contains function prototypes for functions that perform input from files on disk and output to files on disk. The header file is <fstream>

26

Module interface diagram lists exported items

Int Power

Float Power

Power module

Implementationis hidden fromview.

27

• Often several program files use the same header file containing typedef statements, constants, or type declarations. It is a compile-time error to define the same identifier twice.

• This preprocessor directive syntax is used to avoid the compilation error that would otherwise occur from multiple uses of #include for the same header file.

#ifndef Preprocessor_Identifier#define Preprocessor_Identifier . . .

#endif

Avoiding Multiple Inclusion of Header Files

28

Using Preprocessor Directive #ifndef

FOR COMPILATION THE DECLARATIONS IN FILE bool.h WILL BE INCLUDED ONLY ONCE

// bool.h // password.h // client.cpp// SPECIFICATION FILE // SPECIFICATION FILE // Main program

#include “bool.h” #include “bool.h”#ifndef BOOL_H #include “password.h”#define BOOL_H

int main ( void)

typedef int Boolean; {

const int TRUE = 1; . . . . . .

const int FALSE = 0; }

#endif

29

Reserved word static

• It is possible to declare within a function defination a local object that will persist for the entire duration of the program.

• When the value of a local object must persist across invocations of the function, an ordinary automatic object cannot be used.

• The solution is to declare the local object as static.• Though its value persists across invocations of it’s

function, the visibility remains limited to it’s local scope.

30

ctype module interface diagram

isalpha

isdigit

islower

tolower . . .

ctype module

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // SPECIFICATION FILE ( ctype.h )

// PRE: Assigned (ch)

// - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

int isalpha ( int ch ) ; // POST: FCTVAL is nonzero, if ch is a letter: ‘A’. .’Z’, ‘a’. .’z’ // == 0, otherwise

int isdigit ( int ch ) ; // POST: FCTVAL is nonzero, if ch is a digit: ‘0’ . . ‘9’ // == 0, otherwise

int islower ( int ch ) ; // POST: FCTVAL is nonzero, if ch is lowercase: ‘a’ . . ‘z’ // == 0, otherwise

int tolower ( int ch ) ; // POST: FCTVAL == lowercase equivalent, if ch is uppercase // == ch, otherwise

32

Recall that . . .

char str [ 8 ];

str is the base address of the array. We say str is a pointer because its value is an address. It “points” to the memory location of a char.

str [0] [1] [2] [3] [4] [5] [6] [7]

‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’

6000

33

These are equivalentvoid SomeFunc ( char str[ ] );

// str is the base address of an array of char

void SomeFunc( char* str );

// str is a pointer to an object of type char

str [0] [1] [2] [3] [4] [5] [6] [7]

‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’

6000

34

string module interface diagram

strlen

strcmp

string module

strcpy

strcat

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // SPECIFICATION FILE ( string.h )

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

unsigned strlen ( const char* str ) ;

// PRE: str is a null-terminated string // POST: FCTVAL == length of str (not counting ‘\0’ )

int strcmp ( const char* str1, const char* str2 ) ;

// PRE: str1 and str2 are null-terminated strings // POST: FCTVAL < 0, if str1 < str2 lexicographically // == 0, if str1 == str2 “ // > 0, if str1 > str2 “

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// SPECIFICATION FILE continued ( string.h )

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

char* strcpy ( char* toStr, const char* fromStr ) ;

// PRE: fromStr is a null-terminated string // && toStr is large enough to hold the result // POST: fromStr, including ‘\0’ has overwritten toStr, // && FCTVAL == base address of toStr

char* strcat ( char* toStr, const char* fromStr ) ;

// PRE: toStr and fromStr are null-terminated strings // && toStr is large enough to hold the result // POST: fromStr, including ‘\0’ is joined to end of toStr, // && FCTVAL == base address of toStr

37

C++ Data TypesC++ Data Types

Structured

array struct union class

Address

pointer reference

Simple

Integral Floating

char short int long enum

float double long double

unsigned

38

Data Abstraction

• We've said already that algorithms depend on control abstraction and data abstraction

• We've learned that control abstraction has to do with the order the instructions are executed.

• Functional abstraction is important and separate the what from the how

• Data abstraction consists in separating the data type (values and operations) from how the data type is implemented. Again we are separating the what from the how

• It lets the programmer create data types that are not originally available in the language

39

Abstract Data Types

• Every data type has two characteristics:– A set of values– A collection of operations on these values

• Take for instance the C++ int type– It has a set of values: -32768 to +32767– It has a collection of operations: addition, subtraction,

multiplication, etc.• The standard types do not include real world data such

as a list of employees, a circle, a stack, etc.• Modern languages allow the implementation of ADTs

which are programmer-defined types

40

Abstract Data Types

• The operations have to be appropriate to the type.• Take for instance a EmployeeList data type

– Probably arithmetic operations are not appropriate– We need operations like

•AddEmployee•DeleteEmployee• etc

• To implement an ADT, the programmer must– choose a concrete data representation of the abstract data, using

data types that already exist. These may include other ADTs– Implement each allowable operation in terms of program

instructions

41

Why our Password Module is NOT an ADT

• It uses a concrete data representation• It has a set of operations defined

– getPassword()– validUser()

Why it is not considered an ADT?

Because the module export only a single password object

It is not possible for the importer to declare and manipulate several instances of password

42

Data Abstraction is . . .

• the separation of the properties of a data type (its value and operations) from the implementation of that data type.

• PURPOSE -- to create new data types not built into the language and to create valid operations for objects (instances) of that type.

43

Data Abstraction

• Separates the logical properties of a data type from its implementation.

LOGICAL PROPERTIES IMPLEMENTATION

What are the possible values? How can this be done in C++?

What operations will be needed? How can data types be used?

44

Abstract Data Type

Is a programmer-defined type with a set of

values and allowable operations for the type.

Some ways to define a new C++ type are:

using typedef

using struct

using class

45

Using typedeftypedef int Boolean;

typedef char String20 [21] ;

String20 message; // variable declarations

Boolean seniorCitizen;