I ns t i t ut eo fMa na g e me nt & Te c hni c a lSt udi e s
OBJ ECTORI ENTED PROGRAMMI NG 500
Ma s t e ri nCo mp u t e rAp p l i c a t i o n www. i mt s i ns t i t ut e . c om
IMTS (ISO 9001-2008 Internationally Certified) OBJECT ORIENTED PROGRAMMING
OBJECT ORIENTED PROGRAMMING
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING CONTENTS: UNIT I
01-43 Basic Concepts of OOP-Structure of C++ -Data Types –Variables –Control Structures –Functions-Classes and Objects –Constructors and Destructors. UNIT II 44-80 Overloading: Function, Operator –Inheritance – Pointers – Virtual Functions – Polymorphism. UNIT III 81-118 Streams in C++ - Stream Classes –Formatted and Unformatted Data – Manipulators – User Defined Manipulators –File Streams –Opening and Closing a File – File Pointer Manipulation –Template Classes and Functions – Exception Handling : Try,Catch,Throw. UNIT IV 119-139 Introduciton to Java –Features of Java –Methods and Classes –Array,Strings and Vector –Inheritance –Packages and Interfaces. UNIT V 140-169 Exception Handling – Multithreading –Applets –Graphics
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
1
UNIT I BEGINNING WITH C++ The first version of C++ was used internally in AT&T in August 1983. The name “C++” was used late that year. The first commercial implementation was released on October 1985. The name C++(pronounced “see plus plus”) was coined by Rick Mascitti in the summer of 1983. The name signifies the evolutionary nature of the changes from C; “++” is the C increment operator. The slightly shorter name “C+” is a syntax error. Connoisseurs of C semantics find C++ inferior to ++C. The language is not called D, because it is an extension of C, and it does not attempt to remedy problems by removing features. The name C++ was suggested by Rick Mascitti. It was first used in December of 1983 when it was first edited into the final copies by Stroustrup in 1984. The “C” in C++ has a long history. Naturally, it is the name of the language Dennis Ritchie designed. C’s immediate ancestor was an interpreted descendant of BCPL called B designed by Ken Thompson. BCPL was designed and implemented by Martin Richards from Cambridge University while visiting MIT in the other Cambridge. BCPL in turn was Basic CPL, where CPL is the name of a rather large and elegant programming language developed jointly by the universities of Cambridge and London. Before the London people joined the project “C” stood for Cambridge and later it denotes Combined. Unofficially “C” stood for Christopher because Christopher was the main power behind CPL. STRUCTURE OF C++ PROGRAM The following statements has to be included to define the structure of a C++ program as, 1. Include the preprocessor directives or header files. 2. Define a class. 3. void main() 4. { 5. variable declaration; 6. object declaration; 7. Invoke the methods through objects. 8. input statements; 9. display the result 10. }
A SIMPLE C++ PROGRAM & AN EXAMPLE WITH CLASS Example: #include<iostream.h> class test { private: int a; public: void getdata() { cin>>a; } void putdata() {cout<<a; } }; void main() { test t1; t1.getdata(); t1.putdata(); } TOKENS The smallest individual units in program are known as tokens. C++ has the following tokens: Keywords Identifiers
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
2
Constants Strings Operators A C++ program is written using these tokens, white spaces, and the syntax of the language. Most of the C++ tokens are basically similar to the C tokens with the exception of some additions and minor modifications. KEYWORDS The keywords implement specific C++ language features. They are explicitly reserved identifiers and cannot be used as names for the program variables or other user-defined program elements IDENTIFIERS Identifiers refer to the names of variables, functions, arrays, classes, etc. created by the programmer. They are the fundamental requirement of any language has its own rules for naming these identifiers. The following rules are common to both C and C++. Only alphabetic characters, digits, and underscores are permitted. The name cannot start with a digit. Uppercase and lowercase letters are distinct. A declared keyword cannot be used as a variable name. C++ places no limit on its length and , therefore the characters in a name are significant. BASIC DATA TYPES Data refers to a collection of values. Data is represented through constants and variables. Data type refers to the kind of data used in program terminology. Data type classification is depicted in the following figure.
Data Type
Structured /Derived
Scalar /Basic Arrays Numeric
Pointers
Non-Numeric Structure s Character
Integer
Union
Functions
Floating
Scalar /Basic Data Type: The scalar / basic data type is used to represent single values. It is also called as Arithmetic data type. Numeric The numeric data type holds the values of whole numbers or real numbers. Integer The integer data type stores whole numbers and it requires two bytes of memory. Of the sixteen bits, the leftmost bit is reserved for the sign. If it is 0, then the value is taken as positive and if it is 1 then the value is taken as negative. The coding is done as per the 2’s complement method. Representation of Integer data type is int. The values that can be stored as int data type should be in the range of -32768 to 32767.The computer take the values in a circular way and modify any value beyond the range to be a value with in the range. Hence -32769 is taken as 32767, -32770 is taken as 32766. Similarly 32768 is taken as -32767. In the storage economy there is a need to store a large amount of value, for this extensions have been created. The following table describes the various int data types with qualifiers.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING Type short int 1 unsigned short int unsigned int long int 4 unsigned long int
Bytes 1 2 4
3
Range -128 to 127 0 to 255 0 to 65535 -2147483648 to 2147483647 0 to 4294967295
Real Numbers This data type is used to store numeric values with decimal points. This is of two categories such as float and double. Float Data Type For the float data type, the compiler reserves four bytes of memory. The most significant bit represents the sign of value. The representation of float data type is float. In the float data type the float value prints up to six decimal places. Double Data Type The double data type also represents decimal values with up to 12 decimal places. A value of double data type requires 8 bytes of memory. In the default format specification in printing a double data type value it will print values with only 6 decimal places. The double data type under %.12lf will print up to 12 decimal places. The extension in double data type is long double which requires 10 bytes of memory to store a value. Non –Numeric Data Type The non-numeric data type stores the alphanumeric values. This is represented as char. It requires only one byte of memory. The character is a single character. In computers, all information is stored as binary digits. The character is also stored as a sequence of 8 bits. A standard code called as the ASCII (American Standard Code for Information Interchange) is used to represent character in bit format. The ASCII value for ‘A’ is 65.
Constants The value, which never changes during the execution of a program, is called as constants. There are three types of constants and they are as follows, Constants Numeric Character String Integer
Real
Single precision (Float)
Double precision (double)
Decimal Octal Hexadecimal Integer Constant: It is a sequence of digits without a decimal pt. Rules: 1. It must have at least one digit. 2. Comma is not allowed. 3. Special chars are not allowed. 4. Its symbol ‘-‘can occur only at the left most end of the no. 5. An integer constant may end with l (or) L representing long integer, u (or) U representing unsigned integer, of ul (or) UL representing unsigned long integer. Decimal Integer Constant A decimal integer constant is formed having the digits 0 to 9. The base for a decimal integer constant is 10. * Valid
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING 1. 0 2. 1 3. +5 4. -1 5. 625
4
6. 983678 L 7. 6000 U
* Invalid 1. 2. 3. 4.
351, 123 – comma is not allowed 517/ 735 - / is not allowed & 517 – special char is not allowed 75.5 – decimal pt is not permitted.
Octal Integer Constant An octal integer constant is formed from the octal number system 0 to 7, with a leading 0(zero) to identify the constant as octal constant. * Valid 1. 00 2. 01 3. 0627 4. -07757 * Invalid st 1. 627 – 1 digit must be 0. 2. 0627 – its digits 0 to 7 only to be used. 3. 06.27 – decimal pt is not allowed. HexaDecimal Constant A Hexadecimal integer constants is formed from its Hexadecimal number system 0 to 9 and A to F (either lower (or) upper case letters), leading with 0X (or) 0x (Zero X). The characters A to F represent the value 10 to 15. * Valid 1. 0x9A 2. 0xAB25 * Invalid 1. 626 – Not leading with 0x or 0X. 2. 0626 – x (or) X is missing after. 3. 0x627.1 – decimal pt is not allowed. Floating point constant: Any number with a decimal point is called a floating point constant (or) a real constant. It is also known as single precision constant. It can be written in the exponent form. An exponent is written as an e (or) E followed by a –ue integer. An exponent form consists of a mantissa of as exponent. 7 Eg: 0.58x10 can be written as 0.58 e 7 Here the numbers before the letter e or E is called as mantissa and the numbers after the letter e or E is called as exponent part. Rules: 1. The mantissa must have at least one digit of a decimal point. 2. The mantissa is followed by the letter E (or) e of its exponent. 3. Its exponent is always as integer with at least one digit. 4. A sign for the exponent is optional. 5. Floating point constants may end with f (or) F. * Valid 1. 0.0 4. 527.45F 2. 1.0 5. 4.0E-67 3. 0.5 6. 1.333E+6 * Invalid 1. 5 - decimal point missing 2. 5, 27.415 - comma is not allowed. 3. 65.75E1.5 – its exponent is to be an integer quantity.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING 4.5. 38.7E
5
- exponent part is incomplete.
Double precision It is similar to a single precision Floating pt. constant, but with higher range of values and greater precision. Double precision may end with l (or) L representing long double. Character Constant: The single character written within single quotes is called as a character constant. A character may be alphabets, digits, special chars. * Valid 1. 2. 3. 4. 5.
‘x’ ‘z’ ‘8’ ‘?’ ‘t’
* Invalid 1. ‘ ‘ - No char inside single quotes. 2. c - No single quotes 3. “k” - Only single quotes are allowed. 4. / y - Single quote is missing. 5. /sum’- single char is allowed. String constants: The sequence of characters is called as a string. A string constant is a sequence of zero or more chars enclosed within double quotes. It is also known as string literal. * Valid 1. “ c program language” 2. “x” 3. “626” 4. “A + B” 5. “(empty (or) null string)” * Invalid 1. Program 2. ‘Area’
- double quotes are missing -only double quotes are allowed.
The null character (\o) is automatically appended at the end of the string. The null character is a hidden one. Variables The value which changes during the execution of a program is called as variables. Variable is also called as the named storage location. Each variable has a memory address. The information stored in the location is called as the value of the variable. Rules : 1. Variables are formed by using alphabets, Digits, underscore [a_b]. The first character should be an alphabet. 2. No special characters are allowed except underscore symbol. 3. Reserved words can not be variable names. 4. Maximum number of chars in a variable is 31. Some compilers recognize only the first eight characters. 5. Upper and lower case letters are significant. Usually C variables are in lower case. Declaration of variables In C++ all variables must be declared. When a variable is declared it indicates the name of the variable and its type. The purpose of declaring a variable is to indicate the information about the variable to the C compiler. Syntax Data-type variable list; Examples int a,b,c; float f,f1;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
6
char a; char a[40] – to represent a string. double s; unsigned int n; short int s; long int l1;
Operators and Expressions Operators are the symbols used in the programming language for manipulations. Variables in which operators act upon are called operands. The operators are classified into three types. They are, 1. 6.1 Unary operator – Requires only one operand. 1.6.2 Binary operator – Requires two operands. 1.6.3 Ternary operator – Requires three operands. Unary Operator: Unary minus is the only unary operator. This operator is used to indicate the negative value of a variable. Eg int a = -10; Binary Operator: The binary operators are classified into eight types as, 1.6.2.1 Arithmetic Operators 1.6.2.2 Relational Operators 1.6.2.3 Logical Operators 1.6.2.4 Assignment Operators 1.6.2.5 Increment and Decrement Operators 1.6.2.6 Bitwise Operators 1.6.2.7 Special Operators Arithmetic Operators: Arithmetic Operators are used to perform arithmetic calculation. Operators + * (asterisk) / (slash) %
Operation Addition Subtraction Multiplication Division (Gives only quotient) Modulus (Gives only remainder)
There is no operator for exponentiation in C; but a built – in function to find the exponentiation is pow ( ). Arithmetic expressions are formed by using arithmetic quantities of arithmetic operators. They are also known as numeric expressions. Points to Ponder: The division operator / gives quotient value. If both the operators of / are integers, the result is also an integer. If the division operation is carried out with floating point numbers or one floating point number and one integer then the result is a floating point quotient. Eg: .(Integer expressions) Assume x = 15 y = 8 Integer expression Value of expression X+Y 23 -3-8 -11 X*Y 120 -19 % (-8) -3 1/2 0 X/4 1 X/5 3 Character expressions: Ch1 = ‘A’
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
7
Ch2 = ‘C’ Ch3 = ‘1’ For character expression, the equivalent ACSII value of the character is taken and the operation is performed. 1. 2. 3.
ch1 + ch2 ASCII value of A is 65 and C is 67 so total is 132. ch1 + 3 68 = D 65 + 3 ch3 – ‘1’ 0 = NUL 49 – 49
Floating expressions: F1 = 3.147 F2 = 5.0
d1 = 0.333333 d2 = 0.000005
Float / double expression F1 + F2 F1 – 2.012 -6.43 * D1 D2 / (-0.35)
value 8.147000 1.135000 -2.143331 -0.000014
Relational Operators:
Relational operator > >= < <=
These operators are used to test (or) compare two numeric values (or) expressions. They require 2 operators. The operands may be scalar data types (or) pointers. Relational expressions are formed with the help of the relational & equality operators. Meaning Greater than Greater than (or) equal to Less than Less than (or) equal to
Equality operator == !=
Meaning Equal to not equal to
Eg: X = 8 ch = 56
1. 2. 3. 4. 5.
Expression 5<6 X<=5 ch > ‘c’ 51=6 ‘p’ = = ‘p’
Result 1 (true) 0 (false) 0 (false) 1 (true) 0 (false).
Logical operators: In C, there are 2 binary logical operators, they are as follows, && (AND), | | (OR) and One unary logical operator! (NOT). Logical operators Logical operator Meaning && logical AND || logical OR ! logical NOT Logical Expression: A logical expression is any valid combination of logical values, variables & logical operators.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING Eg:
X=5
1. 2. 3. 4. 5.
X && 7 7||6 !0 ! (X = =Y) (X > 10) && Y
8
Y=0 Result -
-
0 0
Remarks T && F
1 1 1
T||7 NOT (False) NOT (False) False && False
Assignment Operators: The operator is used to assign a value to a particular variable. In C, there are two categories of assignment operations namely Simple assignment Compound / Short Hand assignment Simple Assignment The general format for simple assignment is, Variable = expression Eg:
1. X = 5 2. Y = X 3. Area = 3.14 * r * r Compound/ Short Hand Assignment: The general format for simple assignment is, Variable operator = expression The operator can be any one of the following + - * / % << >> & ^ | Eg: 1. 2. 3. 4. 5. 6. Note:
Compound Assignment a+=5 a-=b a * = b3 a/=b a<<=2 a / = (b + c)
Equivalent Simple Assignment a=a+5 a = a- b a = a * b3 a=a/b a=a<<2 a = a / (b + c)
It is useful in multiple Assignments. a=b=0 ; is placed at the end of an assignment expression. Increment & Decrement Operators Increment operator ++ Decrement operator – They are also known as auto - increment and auto – decrement operators. The operand must be a variable, but not a constant or an expression. The ++ operator increments the operand by one, and the --operator decrements the operand by one. The operator ++ (or)-- may precede (or) succeed the operand. These operator execute much faster.If the operator ++ (--) precedes the operand, the operand will be incremented (decremented) by one before it is used. Eg:
For Eg: If p = 7 then m = p++; [Post increment] Assigns value seven to m and then increments p by 1. But m = ++ p[Pre increment]; Increments p by one then assigns eight to m. Valid Format: 1. X ++ 2. Y - 3. ++ P - 4. - - P ++ 5. - - X - -
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
9
6. + + X + + Invalid 1. ++ (a + b) – expression is not allowed as an operand. 2. - - 5 – constant is not allowed as an operand. Bitwise Operators: C differs from the other High-level languages by permitting direct manipulation of the bits stored in the system. C provides six operators for bit memory manipulation. Operator & | ^[caret] << >> ~[tilde]
Meaning bitwise AND bitwise inclusive OR bitwise exclusive OR (XOR) left shift Right shift One’s complement (unary) Fig: Classification of Bitwise operators Bitwise
Binary Bitwise
Bitwise logical
Unary Bitwise
Shift
One’s Complement (~)
Bitwise AND (&): Bitwise Bitwise Left shift Right Bitwise The operator & performs a bitwise AND between 2 operands. AND exclusive OR (<<) shift (>>) inclusive OR The & operators Compared bits Result 0&0 0 0&1 0 1&0 0 1&1 1 Eg: a = 5 (8 bit operation) B=3 Evaluation 1. a&b 00000101 & 00000011 00000001 O / P Decimal: 1 2.
- 20 & 50 – 11101100 (using 2’s complements) &00110010 00100000 = 32 Bitwise Inclusive OR (|) The OR operator perform a bitwise OR between two operands. Compared Bits 0|0 0|1 1|0 1|1
Result 0 1 1 1
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
Eg: 1.
Expression A/B
Evaluation 00000101 00000011 00000111
|
2.
10
- 20 / 50
Result (Decimal) 7
11101100 00110010 11111110
|
-2
Bitwise Exclusive OR (^) The operator ^ performs a bitwise Exclusive OR between operands.
Eg: 1.
2.
Compared Bits Result 0^0 0^1 1^0 1^1 Expression Evaluation A/B 00000101 ^ 00000011 00000110 - 20 ^ 50
0 1 1 0 Result (Decimal) 6
11101100 00110010 11011110
- 34
Shift operators: The right shift operator >> and the left shift operator << move the bit patterns to the right (or) left respectively Syntax: Constant shift – operator n (Or) Variable shift – operator n Where shift – operator is any one of the shift operators >> & <<. N is the number of bit positions to be shifted. For eg: 10101101 – shifted by 3 bit positions. Actual bit position: 1
0
1
0
1
1
0
1
After the right shift
operations:
0
0
0
1
0
1
0
1
1
0
1
Filled bits (Logical fill) Vacated bits
After the left shift operation:
1
0
1
1
Vacated bits
0
1
0
1
0
0
0
Filled bits
One’s complement operator
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
11
One’s complement operator ~ requires one operand. This operator converts all 1 – bits to 0 and 0 – bits to 1 of the binary perform of the operand. The result is One’s complement of the operand. Eg:
Expression
Binary repression
One’s Binary
~ 17
~ 00010001
11101110
238
~5
~ 00000101
11111010
-
Complement decimal
Operator Precedence and Associativity When several operators appear in one expression, evaluation takes place according to certain predefined rules, called Hierarchy Rules. These rules specify the order of evaluation, called precedence level, (or) priority of operator (or) hierarchy of operators. Precedence level 1
2
3
4 5 6
7 8 9 10 11 12 13 14
15
operator () [] . ! ~ ++ -& * / % + Subtraction << >> < <= > >= == != & ^ | && || ?: = + = -= * =/=%= >> = << = &= ^= = / = ,
operation Associativity Function call Left to Right Array subscript Left to Right Dot Left to Right Arrow Left to Right Logical Not Right to Left One’s complement Right to Left Unary minus (negation) Right to Left Increment Right to Left Decrement Right to Left Address of Right to Left Multiplication Left to Right Division Left to Right Modulus Left to Right Addition Left to Right Left to Right Left shift Left to Right Right shift Left to Right Less than Left to Right Less than or equal toLeft to Right Greater than Left to Right Greater than or equal toLeft to Right Equal to Left to Right Not equal to Left to Right Bitwise AND Left to Right Bitwise XOR Left to Right Bitwise OR Left to Right Logical AND Left to Right Logical OR Left to Right Conditional Left to Right Simple of Compound Assignment Left to Right Comma
Left to Right
Eg: 1. 2. 3. 4.
Expression A--%2 X/y-A * = b – 32 !a==0
Order of Evaluation a - - , (a- -) % 2 y - -, x / (y - -) b – 32 a * = (b-32) ! a, (! a) = = 0
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
-
OBJECT ORIENTED PROGRAMMING
12
Ternary / Conditional Operator : The operator is named so because it uses three expressions. The syntax is as follows, Variable = condition? expression1:expression2. There are two symbols in this operator. The operator first verifies the condition, if the condition is true expression1 is evaluated otherwise expression2 is evaluated. This can also be replaced with the if-else statement. The operator can be used only for simple expressions. Eg : Big = a>b?a :b; In the example if the value of a is greater than b, then a value is used to the variable big otherwise b value is assigned to big. Flowchart :
Condition
False
Expression2
True Expression1
ESCAPE SEQUENCE A character constant represent a single character and a string constant represents a zero or more characters. Escape sequence is a character representation that may appear in a char constant (or) in a string constant. The chars on its keyboard can be printed (or) displayed by a press on its key. But some chars such as line feed, form feed, tab etc cannot be printed (or) displayed directly. Certain nonprinting chars, as well as the backslash (\) and its apostrophe (‘), can be expressed in terms of Escape sequences.C uses ‘\’(back slash) as the escape character. An escape sequence always begins with a backward slash and one (or) more special characters follow it. Escape sequences table Escape sequence Meaning Result at execution time /a /b /f /n /r /t /v // \? /’ /” /0
Bell Sound Produces an Bell sound Backspace Moves the active position to the previous position on the current line. Form Feed Moves the active position to the initial position of the next page. New Line Moves the active position to the initial position of the next line. Carriage Return Moves the active position to the initial position of the current line. Horizontal tab Moves the active position to the next horizontal tabulation position. Vertical tab Moves the active position to the next Vertical tabulation position. Backslash Presents with a backslash (/) Question mark Presents with a question mark? Single quote Presents with a single quote’ Double quote Presents with a double quote” Null char End of string.
USER-DEFINED DATA TYPE Structures and Classes In C++ beyond the use of Structure and Union, the special user defined data type is given which is the class type. The class variables are known as objects, which are the central focus of object-oriented programming.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
13
Enumerated Data Type An enumerated data type is another user-defined type which provides a way for attaching names to numbers, thereby increasing comprehensibility of the code. The enum keyword (from C) automatically enumerates a list of words by assigning them values 0,1,2, and so on. This facility provides an alternative means for creating symbolic constants. The syntax of an enum statement is similar to that of the struct statement. Examples: enum shape {circle, square, triangle}; enum color {red,blue, green, yellow}; enum podition {off, on}; The enumerated data types difer slightly in C++ when compared with those in ANSI C. In C++, the tag names shape, color, and position become new type names. That means we can declare new variables using these tag names. Examples: Shape ellipse; // ellipse is of type shape Color backgorund; // background is of type color ANSI C defines the types of enums to be ints. In C++, each enumerated data type retains its own separate type. This means that C++ does not permit an int value to be automatically conerted to an enum value. Examples: Color background = blue; // allowed Color background = 7; // Error in C++ Color background = (Color) 7; // OK However, an enumerated value can be used in place of an int value. int c = red; // vaild, color type promoted to int. By default, the enumerators are assigned integer values starting with 0 for the first enumerator, 1 for the second, and so on. We can over- ride the default by explicitly assigning integer values to the enumerators. For example, enum color {red, blue = 4, green = 8}; enum color { red = 5, blue, green}; are valid definitions. In the first case, red is 0 by default. In the second case, blue is 6 and green is 7. Note that the subsequent initialized enumerators are larger by one than their predecessors. C++ also permits the creation of anonymous enums(i.e., enums without tag banes). Example: enum {off, on}; Here, off is 0 and on is 1. These constants may be referenced in the same manner as regulate constants. Examples: int switch_1 = off; int switch_2 = on; DERIVED DATA TYPE Arrays The application of arrays in C++ is similar to that in C. The only exception is the way character arrays are initialized. When initializing a character array in ANSI C, the complier will allow us to declare the array size as the exact length of the string constant. For instance, Char string[3] = “xyz”; is valid in ANSI C. It assumes that the programmer intends to leave out the null character \0 in the definition. But in C++, the size should be one larger that the number of characters in the string. Char string[4] = “xyz”; // O.K. for C++ Functions Functions have undergone major changes in C++. While some of these changes are simple, others require a new way of thinking when organizing our programs. Many of these modifications and improvements were driven by the requirements of the object-oriented concept of C++. Some of these were introduced to make the C++ program more reliable and readable. Pointers Pointers are declared and initialized as in C .Examples: int * ip; // int pointer ip = &x; // address of x assigned to ip *ip = 10; // 50 assigned to x through indirection C++ adds the concept of constant pointer and pointer to a constant. Char * const ptr2a = “GOOD”; // constant pointer We cannot modify the address that ptr1 is initialized to, int cond * ptr2 =&m; // pointer to a constant
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
14
Ptr2 is declared as pointer to a constant. It can point to any variable of correct type, but the contents of what is points to cannot be changed. We can also declare both the pointer and the variable as constants in the following way: Const char * conts cp = “xyz”; This statement declares cp as a constant pointer to point the string which has been declared as constant. In this case, neither the address assigned to the pointer cp or the contents it points to can be changed. Pointers are extensively used in C++ for memory management and achieving polymorphism. SYMBOLIC CONSTANTS There are two ways of creating symbolic constants in C++; 1. Using the qualifier const. 2. Defining a set of integer constants using enum keyboard. In both C and C++, any value declared as const cannot be modified by the program in any way. However, there are some differences in implementation. In C++, we can use const in a constant expression, such as const size = 10; Char name [size]; This would be illegal in C. const allows us create typed constants instead of having to us #define to create constants that have no type information. Const size = 10; Means Conts int size = 10; The named constants are just like variable except that their values cannot be changed C++ requires a const to be initialized. ANSI C does not require an initializer; if none is given, it initializes the const to 0. The scoping of const values differs. A const in C++ defaults to the internal linkage and therefore it is local to the file in which they are declared. However, they can be made local by declaring them as static. To give a const value external linkage so that it can be referenced from another file, we must explicitly define it as an extern in C++. Example: extern const total = 100; Another method of naming integer constants is as follows: enum {x,y,z}; This defines x,y and z as integer constants with value 0,1, and 2 respectively,. This is equivalent to: const x = 0; conts y = 1; conts z = 2; We can also assign values to x, y, and z explpicitly. enum{x=100, y=50,z=200}; Such value can be any integer values.
TYPE COMPATIBILITY C++ is very strict with regard to type compatibility as compared to C. for instance; C++ defines int, short int, and long int as three different types. They must be cast when their values are assigned to one another. Similarly, unsigned char, char, and signed char are considered as different types, although each of these has a size of one byte. In C++, the types of values must be the same for complete compatibility. Otherwise, a cast must be applied. These restrictions in C++ are necessary in order to support function overloading where two functions with the same name are distinguished using the type of function arguments. Another notable difference is the way char constants are stored. In C, they are stored as ints. Therefore, sizeof(‘x’) is equvalent to sizeof(int) in C. But, in C++, char is not promoted to the size of int and therefore, sizeof(‘x’) equals sizeof(char).
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
15
DECLARATION OF VARIABLES In C, all variables must be declared before they are used in executable statements. This is true with C++ as well. However, there is a significant difference between C and C++ with regard to the place of their declaration in the program. C requires all the variables to be defined at the beginning of a scope. When we read a C program, we usually come across a group of variable declarations at the beginning of scope level. Their actual use appears elsewhere in the scope, sometimes far away from the declaration. C++ allows the declaration of a variable anywhere in the scope. This means that a variable can be declared right at the place of its first use. This makes the program much easier to write and reduces the errors that may be caused by having to scan back and forth. It also makes the program easier to understand because the variables are declared in the context of their use. The example below illustrates this point. main ( ) { float x; float sum = 0; for(int i=1;i<5;i++) { cin >> x; sum = sum+x; } float average; average = sum / I; count << average; } The only disadvantage of this style of declaration is that we cannot see at a glance all the variables used in a scope. DYNAMIC INITIALIZATION OF VARIACLES One additional feature of C++ is that it permits initialization of the variables at run time. This is referred to as dynamic initialization. Remember that, in C, a variable must be initialized using a constant expression and the C compiler would fix the initialization code at the time of compilation. However, in C++, a variable can be initialized at run time using expressions at the place of declaration. For example, the following are valid initialization statements. ……… ………. int n = strlen(string); ……… float area = 3.24159 * rad * rad; This means that both the declaration and initialization of a variable can be done simultaneously at the place where the variable is used for the first time. The following two statements in the example of the previous section float average; average = sum / i; can be combined into a single statement: float average = sum / i; Dynamic initialization is extensively used in object-oriented programming. We can create exactly the type of object needed using information that is known only at the run time. REFERENCE VARIABLES C++ introduces a new kind of variable known as the reference variable. A reference variable provides an alias (alternative name) for a previously defined variable. For example, if we make the variable sum a reference to the variable total, then sum and total can be used interchangeably to represent that variable. A reference variable is created as follows: data-type & reference-name = variable-name; Example: float total = 100; float & sum = total;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
16
total is a float type variable that has already been declared. Sum is the alternatie name declared to represent the variable total. Both the variables refer to the same data object in the memory. Now, the statements cout << toatl; and cout << sum; both print the value 100. the statement total = total + 10; will change the value of both total and sum to 110. A reference variable must be initialized at the time of declaration. This establishes the correspondence between the reference and the data object that it names. Note that the initialization of a reference variable is completely different from assignment to it. Note that C++ assigns additional meaning to the symbol &. Here, & is not an address operator. The notation & means reference to float. Other examples are: i. int x; int *p =&x; int &m =*p; ii. int & n= 50; The first set of declarations causes m to refer to x which is pointed to by the pointer p and the statement in (ii) creates an int object with value 50 and name n. A major application of reference variables is in passing arguments to functions. Consider the following: Void f(int &x) { x=x+10; } main ( ) { int m = 10; f(m); ………. ……….. } when the function call f(m) is executed, the following initialization occurs: int & x = m; Thus x becomes an alias of m after executing the statement f(m); such function calls are know as call by reference. The value of m becomes 20 after the function is executed. The call by reference mechanism is useful in object-oriented programming because it permits the manipulation of objects by reference and eliminates the copying of object parameters back and forth. Note that the references can be created not only for build-in data type but also for user-defined data types such as structures and classes. References work wonderfully well with these user-defined data types.
OPERATORS IN C++ Scope Resolution Operator The operator is used to indicate to which class an identifier belongs to. Symbol is :: This operator allows to access the global version of a variable. Member Dereferencing Operator These operators are used to access the class members of the class through pointers. The various operators are listed below, * :: ------- To declare a pointer to a member of a class * ------- To access a member using object name and a pointer to that member. -> --------- To access a member using a pointer to that object and a pointer to a member. Memory Management Operator In C the two memory management operators are the calloc and malloc functions. In C++ these two operators are replaced by the new and delete operator. New operator is used to allocate a
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
17
memory when required and delete operator is used to release the memory. The new operator cane be used to create objects of any type. The general syntax is as follows, Pointer variable = new datatype; p = new int; (or) pointer variable = new datatype(value); p = new int(5); When a data object is no longer needed, it is destroyed to release the memory space for reuse. Syntax: delete pointer-variable; Example : delete p; CONTROL STRUCUTRES Decision Making and Branching(Inclusive of Loop Control Structures) The control statements are used to transfer the control from one part of the program to another part. It alters the normal flow of execution. Control Structures
Conditional
Selective
Unconditional
Loop
For Loop
While Loop
Go to
Break
Continue
Do – While Loop
If - Else If – else construct: If – Else - If Conditional Expression Switch - Case If the condition is true, a single (or) a block of statements are executed, otherwise another single (or) block of statements are executed. It is used to select a specific statement based on the specified condition. This statement is used whenever a decision making is involved in a program. If-else construct is called as one-way decision making statement. Syntax: If (expression) { statement 1; } else { statement 2; } Flowchart:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
True
18
False Expression
Statement 1
Statement 2
If there is a simple statement, the braces are optional. If (expression) Statement; The else part may be omitted, if not necessary. If (expression) { Statement 1; } The value of the expression is evaluated first. If the expression returns a true value, the control goes to statement1. If there is no else part and the expression. Return false value then the subsequent statement will be belated. Eg1: if (a > b) cout<< a; else cout<< b; Program1: Write a program to check whether the given integer is odd (or) even. # include <iostream.h> main ( ) { int x; cout<<“Enter an integer \n”; cin>>x; if (x%2 == 0) cout<<“The given number is odd”<< x; else cout<<“The given number is even”<< x; } Nested if – else: If one if – else construct is used within another if – else, it is known as a nested if – else construct. Syntax: If (expression – 1) If (expression – 2) If (expression – 3) { Statement 1; } Else { Statement 2;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING } Else { Statement 3; } (Or) Syntax: If (expression – 1) { If (expression – 2) { If (expression – 3) { statement; } Else { statement 2; } } Else { statement 3; } } If – Else if construct The else if construct follows the if construct to have multiple decision making. Syntax: If (expression – 1) { statement 1; } else If (expression – 2) { statement 2; } else If (expression – 3) { statement 3; } Else { statement 4; } Program 1: Write a program to check whether the entered char is vowel (or) not. # include <string.h> # include <stdio.h> main ( ) { char ch; cout<<”Enter a char \n”; ch = getchar ( ); If (ch > = ‘A’ && ch < = ‘z’ || ch > = ‘a’ && ch < = ‘z’) { If (ch = = ‘a’ || ch = = ‘e’ || ch = = ‘i’ || ch = = ‘o’ || ch = = ‘u’) cout<<“Given char is vowel \n”;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
19
OBJECT ORIENTED PROGRAMMING else if (ch = = ‘A’ || ch = = ‘E’ || ch = = ‘Z’ || ch = = ‘O’||ch== ‘U’)
20 cout<<“Given char is vowel
\n”; else cout<<“Given char is not a vowel \n”; } else cout<<“Given letter is not a character \n”; } Switch – case construct: This statement is as an alternative to if – else (or) if – else if statement. It is used to transfer the control to one of the corresponding multiple branches. Syntax: Switch (expression) {case construct -1: { statement; break; } case construct -2: { statement; break; } case construct –n: { statement; break; } default: {Statement; break; } } // End of switch Note:
All the cases should be distinct. The constants following the cases are known as case labels. A colon ( : ) must be placed at the end of each case label & default. The braces({}) following the labels are optional. The expression must be an integer (or) character expression. st The given expression is evaluated 1 and its value is matched the case labels. If it is yes, the statement following the case will be executed. If there is no match with any of the case labels, the stateme nt following the default will be executed. The default part is optional. Eg 1: Write a program to write any given number. (between 0 to 9) in words. Eg: i/p 0 – o/p Zero i/p 1 – o/p One #include<stdio.h> main ( ) { int digit;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING cin>>digit; switch (digit) { case 0: cout<<“zero”; break; case 1: cout<<”one”; break; , , ,
21
Similarly do for case 2 – 8.
case 9: cout<<“Nine”; break; } } While Construct: It is called as an entry-controlled loop. The conditions are verified at the beginning and if the condition is true the statements following while keyword is executed. Syntax: While (expression) { statement; } Entry Flow chart:
False
Expression
True Statement
Execution: The expression is evaluated first. The blocks of statements are executed repeatedly until the value of expression is false. Eg 1: X = 1; while (x < 10) { cout<<”X is”<<x; x = x + 1; } Eg 2: # include <iostream.h> main ( ) { int i = 100; while (i) { cout<<i; i = i – 10;
}}
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
22
Do – While Statement: The Do-While statement is called as exit-controlled loop. The condition is verified at the last. If the condition is true, the statements the statements will be executed otherwise it continues to the next statement. The statements will be executed at least once even if the condition is false. Syntax: do { Statement; } While (expression); Flow Chart:
Entry
Statement
True Expression 1
False
Exit Execution: The block of statements are executed first. Then the expression is evaluated. The block of statement are executed repeatedly until the value of expression is false. Eg: 1 x = 1; do { cout<<“x value is ”<< x; x = x + 1; }while (x < 10); Note:
Here the block of statements are executed at least once. Then the condition is tested. So the loop is executed 9 times. Suppose x = 10, the control comes out of the loop.
Difference between while and do- while: While Loop Do-While Loop 1. Entry-Controlled Loop Exit-Controlled Loop 2. The statements are not executed The statements are executed at least even once. once even if the condition is false. For statement: For statement is also an entry-controlled loop. After initialization the condition is verified, if the condition is true the statements will be executed other wise it is terminated. Syntax: for (expression-1; expression-2; expression-3) { statement: } Execution: Step 1: First, expression -1 is evaluated to initialize a counter.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
23
Step 2: Expression -2 is evaluated to check the condition for execution. If the condition is true the statement in the loop is executed. Step 3: Then the expression-3 is evaluated to continue the process until the condition is true. Note: Expression -1 initializes the counter Expression -2 is a condition for execution. Expression -3 increments or decrements the counter. Flow chart: Entry
Expression -1
False Expression2
True Statement
Expression - 3
Note2: Exit Any of the 3 expressions can be omitted, but the semicolon (;) must be placed there. Valid eg: 1.
for ( ;expression -2; expression -3) { Statement; } If expression-1 is omitted the value is initialized to zero.
2.
for (expression -1; expression -2; ) { Statement; } If expression-3 is omitted then the value is either incremented or decremented based on condition.
3.
for ( ;expression -2; ) { Statement; } for ( ; ;) { Statement; } This leads to an infinite loop.
4.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
24
Eg 1: #include<stdio.h> main ( ) { int x; for (x = 1; x < 10; x ++) cout<<“x is “<< x; } FUNCTION IN C++ Dividing a program into functions is one of the major principles of top-down, structured programming. Another advantage using functions is that it is possible to reduce the size of a program by calling and using them at different places in the program. In fact, C++ added many new features to functions to make them more reliable and flexible. Like C++ operators, a C++ function can be overloaded to make it perform different tasks depending on the arguments passed to it. Most of these modifications are aimed at meeting requirements of object-oriented facilities. THE MAIN FUNCTION ANSI C does not specify any return type for the main ( ) function which is the starting point for the execution of a program. The definition of main ( ) would look like this; main ( ) { // main program statements } This is perfectly valid because the main( ) in ANSI C does not return any value.In C++, the main( ) returns a value of type int to the operating system. C++, therefore, explicitly defines main ( ) as matching one of the following prototypes. int main ( ); int main (int argc, char* argv[] ); The functions that have a return value should use the return statement for termination. The main ( ) function in C++ is, therefore, define as follows: int main ( ) { …….. …….. return( 0); } Since the return type of functions is int by default, the keyword int in the main ( ). Header is optional. Most C++ compliers will generate an error or warning if there is no return statement. Turbo C++ issues the warning “Fuction should return a value” and then proceeds to compile the program. It is good programming practice to actually return a value from main ( ).Many operating systems test the return value(called exit value) to determine if there is any problem. The normal conversion is that an exit value of zero means the program ran successfully, while a nonzero value means there was a problem. The explicit use of a return (0) statement will indicate that the program was successfully executed. FUNCTION PROTOTYPING Function prototyping is one of the major improvements added to C++ functions. The prototype describes the function interface to the compiler by giving details such as the number and type of arguments and the type of return values. With function prototyping, a template is always used when declaring and defining a function. When a function is called, the compiler used the template to ensure that proper. Arguments are passed, and the return value is treated correctly. Any violation in matching the arguments or the return types will be caught by the complier at the time of compilation itself. These checks and controls did not exist in the conventional functions. Remember, ANSI C also uses prototyping. But it was introduced first in C++ by stroustrup and the success of this feature inspired the ANSI C and C++. While C++ makes the prototyping essential, ANSI C makes it optional, perhaps, to preserve the compatibility with classic C. Syntax: type function-name (argument-list); The argument-list contains the types and names of arguments that must be passed to the function. Example:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
25
int add(int a,int b); Note that each argument variable must be declared independently inside the parentheses. In a function declaration, the names of the arguments are dummy variables and therefore, they are optional. That is, the form int add(int,int); is acceptable at the place of declaration. At this stage, the complier only checks for the type of arguments when the functions are called. In general, we can either include or exclude the variable names in the argument list of prototypes. The variable names in the prototype just act as placeholders and, therefore, if names are used, they don’t have to match the names used in the function call or in function definition. In the function definition, names are required because the arguments must be referenced inside the function. Example: int add(int x,int y) { return(x+y); } The function add ( ) can be invoked in a program as follows: C=add(a,b); The variable a,b are known as the actual parameters which specify dimensions of C. Their types (which have been declared earlier) should match with the types declared in the prototype. Remember, the calling statement should not include type names in the argument list. We can also declare a function with an empty argument list, as in the following example: Void display( ); CALL BY REFERENCE In traditional C, a function call passes arguments by value. The called function creates a new set of variables and copies the values of arguments into them. The function does not have access to the actual variables in the calling program and can only work on the copies of values. This mechanism is fine if the function does not need to alter the valued of original variables in the calling program. But, there may arise situations where we would like to change the values of variables in the calling program. For example, in bubble sort, we compare two adjacent elements in the list p and interchange their values if the first element is greater than the second. If a function is used for bubble sort, then it should be able to alter the values of variables in the calling function, which is not possible if the call-by –value method is used. The reference variables in C++ permits allow us to pass parameters to the functions by reference. When we pass arguments by reference, the ‘formal’ arguments in the called function become aliases to the ‘actual’ arguments in the calling function. This means that when the function is working with its own arguments, it is actually working on the original data. Consider the following function: void swap(int &a, int &b) { int t = a; a = b; b = t; } Now, if m and n are two integer variables, then the function call swap(m,n); This will exchange the values of m and n using their aliases (reference variables) b and a. In traditional C, this is accomplished using pointers and indirection as follows: void swap1(int *a, int *b) /* Function definition*/ { int t; t =*a; *a=b; *b=t; } This function can be called as follows: swap1(&x,&y); This approach is also acceptable in C++. Note that the call-by-reference method is neater in its approach.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
26
RETURN BY REFERENCE A function can also return a reference. Consider the following function: int &max(int &x, int &y) { if {x>y} return x; else return y; } Since the return type of max( )is int &, the function returns reference to x or y(and not the values). Then a function call such as max(a,b) will yield a reference to either a or b depending on their values. This means that this function call appear on the lift-hand side of an assignment statement.That is , the statement max(a,b)=-1; is legal and assigns -1 to a if it is larger, otherwise -1 to b. INLINE FUNCTIONS One of the objectives of using functions in a program is to save some memory space, which becomes appreciable when a function is likely to be called many times. However, every time a function is called, it takes a lot of extra time in executing a series of instructions for tasks such as jumping to the function, saving registers, pushing arguments into the stack and returning to the calling function. When a function is small, a substantial percentage of execution time may be spent in such overheads. One solution to this problem is to use macro definitions, popularly known as macros. Preprocessor macros are popular in C. The major drawback with macros is that they are not really functions and therefore the usual error checking does not occur during compilation. C++ has a different solution to this problem to eliminate the cost of calls to small function. C++ proposes a new feature called inline function. An inline function is a function that is expanded in line when it is invoked. That is, the complier replaces the function call with the corresponding function code(something similar to macros expansion). The inline functions are defined as follows. inline function-header { function body } Example: inline double cube (double a) { return (a * a* a); } The above inline function can be invoked by statements like c = cube(3,0); d = cube(2.5+1.5); On the execution of these statements, the value of c and d will be 27 and 64 respectively. If the arguments are expressions such as 2.5+1.5, the function passes the value of the expression, 4 in the case. This makes the inline feature far superior to macros. It is easy to make a function online. All we need to do is to prefix the keyword inline to the function definition. All inline functions must be defined before they are called. The benefits of inline functions diminish as the function grows in size. At some point the overhead of the function call become small compared to the execution of the function, and the benefits of inline functions may be lost. In such cases, the use of normal functions will be more meaningful. Usually, the functions are made inline when that are small enough to be defined in one or two lines. Example: inline double cube(double a) {return (a* a* a);} Remember that the online keyword merely sends a request, not a command, to the complier. The compiler may ignore this request if the function definition is too long or too complicated and complier the function as a normal function. 1.For functions returning values, if a loop, a switch, or a goto exists. 2.For functions not returning values, if a return statement exists. 3.If functions contain static variables. 4.If inline functions are recursive. Note: #include <iostream.h> #include <stdio.h> inline int square (int x)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
27
{ return( x * x); } main ( ) { int n,s; cin>>n; s= square(n); cout<<â&#x20AC;?Square of a Number isâ&#x20AC;?<<s; } DEFAULT ARGUMENTS C++ allows us to call a function without specifying all its arguments. In such cases, the function assigns a default value to the parameter which does not have a matching argument in the function call. Default values are specified when the function is declared. The compiler looks at the prototype to see how many arguments a function use and alerts the program for possible default values. Here is an example of a prototype (i.e. function declaration) with default values: float si(int p,int n=5,float r=0.12); The default value is specified in a manner syntactically similar to a variable initialization. The above prototype declares a default value number of years(n) and rate of interest(r). A subsequent function call like value = si(5000); passes the value of 5000 to The call Value =sit (5000,5,0.12); passes an explicit value of 0.12 to rate. A default argument is checked for type at the time of declaration and evaluated at the time of call. One important point to note is that only the trailing arguments can have default values. That is, we must add defaults from right to left. We cannot provide a default value to a particular argument in the middle of an argument list. Default arguments are useful in situations where some arguments always have the same value. For instance, bank interest may remain the same for all customers for a particular period of deposit. It also provides a greater flexibility to the programmers. A function can be written with more parameters than are required for its most common application. Using default arguments, a programmer can use only those arguments that are meaningful to a particular situation.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
28
UNIT III CLASS A Class is a way to bind the data its associated functions together. It allows the data(and function) to be hidden, if necessary, from external use. When defining a class, we are creating a new abstract data type that can be treated like any build-in data type. Generally, a class specification has two parts: 1. Class declarations 2. Class function definitions. The class declaration describes the type and scope of its members. The class function definitions describe how the class functions are implemented. The general form of a class declaration is: class class_name { private: variable declarations; function declarations; public: variable declarations; function declarations } The class declaration is similar to a struct declaration. The keyword class specifies that what follows is an abstract data of type class_name. The body of class is enclosed within braces and terminated by a semicolon. The class body contains the declaration of variables and functions. These functions and variables are collectively called members. They are usually grouped under two sections, namely, private and public to denote which of the members are private and which of them and public. The keywords private and public are known as visibility labels. Note that these keywords are followed by a colon. The members that have been declared as private can be accessed only from within class. On the other hand, public members can be accessed from outside the class also. The data hiding (using private declaration) is the feature of object-oriented programming. The use of the keyword private is optional, By default, the members of a class is completely hidden from the outside world and does not serve any purpose. The variables declared inside the class are known as data members and the functions are known as member functions. Only the member functions can have access to the private data members and private functions. However, the public members both functions and data can be accessed from outside the class. The binding of data and functions together into a single class-type variable is referred to as encapsulation. A Simple Class Example A typical class declaration would look like: class item { int b; public: void getdata(int a); void putdata(void); }; Creating Objects Remember that the declaration of item as shown above does not define any objects of item but only specifies what they will contain. Once a class has been declared, we can create variables of that type by using the class name(like any other build_in type variable). For example, item x; Create a variable x of type item. In C++, the class variables are known as objects. Therefore, x is called an object of type item. We may also declare more than one object in one statement. Example item x,y,z;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
29
The declaration of an object is similar to that of variable of any basic type. The necessary memory space is allocated to an object at this stage. Note that class specification, like a structure, provides only a template and does not create any memory space for the objects. Objects can also be created by placing their names immediately after the closing brace, as we did in the case of structures. That is, the definition. class item { ………. ………. } x,y,z; The private data of a class can be accessed only through the member functions of that class. The main ( ) cannot contain statements that access number and cost directly. The following is the format for calling a member function: Syntax: Object-name. function-name (actual-arguments); DEFINING MEMBER FUNCTIONS Member functions can be defined in two places; Outside the class definition Inside the class definition It is obvious that, irrespective of the place of definition, the function should perform the same task. Therefore, the code for the function body would be identical in both the cases. However, there is a subtle difference in the way the function header is defined. Both these approaches are discussed in detail in this section. Outside the Class Definition Member functions that are declared inside a class have to be defined separately outside the class. Their definitions are very much like the normal function. They should have a function header and a function body. Since C++ does not support the old version of function definition, the ANSI prototype from must be used for defining the function header. An important difference between a member function and a normal function is that a member function incorporates a membership ‘identity label’ in the header. This ‘label’ tells the compiler which class the function belongs to. The general form of a member function definition is: Syntax: return-type class-name : : function-name(argument declaration) { function body } The membership label class-name :: tells the compiler that the function function-name belongs to the class class-name, that is the scope of the function is restricted to the class-name specified in the header line. The symbol : : is called the scope resolution operator. For instance, consider the member functions getdata() and putdata() are discussed in the previous section. They may be coded as follows: void item : : getdata(int a) { b=a; } void item : : putdata(void) { cout<<”Value is”<<b; } Since these functions do not return any value, their return-type is void. Function arguments are declared using the ANSI prototype. Several different classes can use the same function name. The ‘membership label’ will resolve their scope. Member functions can access the private data of the class. A non-member function cannot do so. A member function can call another member function directly, without using the dot operator. Inside the Class Definition Another method of defining a member function is to replace the function declaration by the actual function definition inside the class. For example, we could define the item class as follows:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
30
class item { int number; float cost; public: void getdata(int a, floatb); // inline function void putdata9void); { cout <<number<< “\n”; cout<<cost << “\n”; } }; When a function is defined inside a class, it is treated as an inline function. Therefore, all the restrictions and limitations that apply to an inline function are application here. Normally, only small functions are defined inside the class definition. A C++ PROGRAM WITH CLASS [CLASS IMPLEMENTATION] # include <iostream.h> class sample { int no,no1; public: void getdata(int a, int b); void putdata(void); { cout << “ Number:” << no << “\n”; cout << “Second Number : “ << no1 <<”\n”; } }; // ……………….Member Function Definition……………………………. Void sample : : getdata(int a, int b) // use membership label { no =a; no1= b; } // ………………………..Main Program……………….. main( ) { sample x; x.getdata(100,299); x.putdata( ); } This program features the class item. This class contains two private variables and two public functions. The member function getdata( ) which has been defined outside the class supplies values to both variables. Note the use of statements such as no = a; In the function definition of getdata( ). This shows that the member functions can have direct access to private data items. The members function putdata( ) has been defined inside the class and therefore behaves like an inline function. This function displays the values of the private variables number and cost. The program creates two objects, x and y in two different statements. This can be combined in one statement. item x, y; MAKING AN OUTSIDE FUNCTION INLINE One of the objectives of OOP is to separate the details of implementation from the class definition. It is therefore good practice to define the member functions outside the class.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
31
We can define a member function outside the class definition and still makes it inline by just using the qualifier inline in the header line of function definition. Example: class item { ………. ………. public: void getdata(int a, float b); } inline void item : : getdata(int a, float b) { number = a; cost = b; } The memory space for objects is allocated when they are declared and not when the class is specified. This statement is only partly true. The member functions are created and placed in the memory space only once when they are defined as a part of a class specification. Since all the objects belonging to that class use the same member functions, no separate space is allocated for member functions when the objects are created. Only space for member variables is allocated separately for each object. Separate memory locations for the objects are essential because the member variables will hold different data values for different objects. STATIC DATA MEMBER A data member of a class can be qualified as static. The properties of a static member variable are similar to that of C static variable. A static member variable has certain special characteristics; It is initialized to zero when the first object of its class is created. No other initialization is permitted. Only one copy of that member is created for the entire class and is shared by all the objects of that class, no matter how many object are created. It is visible only within the class, but its lifetime is the entire program. Static variables are normally used to maintain values common to the entire class. For example, a static data member can be used as a counter that records the occurrences of all the objects. First, notice the following statement in the program; int item : : count; Note that the type and scope of each static member variable must be defined outside the class definition. This is necessary because the static data members are stored separately rather than as a part of an object. Since they are associated with the class itself rather than with any class object, they are also known as class variables. [STATIC CLASS MEMBER] # include <iostream.h> class item { static int count; int number; public: void getdata(int a) { number =a; count ++; } void getcount(void) { cout << “count:”; cout << count << “\n”; } }: int item : : count: // count DEFINED main( ) {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
32
item a,b,c; a.getcount( ); b.getcount( ); c.getcount( ); a.getdata(100); b.getdata(200); c.getdata(300); cout << “After reading data “ << “\n”; a.getcount( ); /count( ); ///////////////////////////////////////////// PROGRAM 5.4 /////////////////////////////////////// The output would be: Count :0 Count :0 Count :0 After reading data: Count :3 Count :3 Count :3 This static variable count is initialized to zero when the objects are created. The count is incremented whenever the data is read into an object. Since the data is read into objects three times, the variable count is incremented three times. Because there is only one copy of count shared by all the three objects, all the output statements cause the value 3 to be displayed. Static variables are like non-online member functions in that they are declared in a class declaration and defined in the source file. While defining a static variable, some initial value can also be assigned to the variable. For instance, the following definition gives count the initial value 10. int item : : count = 10;
STATIC MEMBER FUNCTIONS Like static member variable, we can also have static member functions. A member function that is declared static has the following properties: A static function can have access to only other static members (functions or variables) declared in the same class. A static member function can be called using the class name(instead of its objects) as follows: Syntax class-name :: function-name; The static function showcount( ) displays the number of objects created till that moment. A count of number of objects created is maintained by the static variable count. The function showcode( ) display the code number of each object. Note that the statement code. Since each object has its own copy of code, the value contained in code represents a unique number of its object. #include<iostream.h> class test { int code; static int count; public; void setcode (void) { code = ++ count; } void showcode(void) { count << “object number:” << code << “\n”; } static void showcount (void)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
33
{ cout << “count: “ << count << “\n”; } }; int test : : count; main( ) { test t1,t2; t1.setcode( ); t2.setcode( ); test : : showcount ( ); test t3; t3.setcode( ); test : : showcount( ); t1.showcode( ); t2.showcode( ); t3.showcode( ); Remember, the following function definition will not work: Static void showcount( ) { cout << code; } ARRAYS OF OBJECTS We know that an array can be of any data type including struct. Similarly, we can also have arrays of variables that are of the type class. Such variables are called arrays of objects. Consider the following class definition: class employee { char name[30]; float age; public: void getdata(void); void putdata(void); }; The identifier employee is a user-defined data type and can be used to create objects that relate to different categories of the employees. Example: employee manager[3]; employee foremen[15]; employee worker[75]; The array manager contains three objects (managers), namely, manager[0], manager[1], manager[2], of type employee class. Similarly, the foreman array contains 15 objects (format) and the worker array contains 75 objects(workers). Since an array of objects behaves like any other array, we can use the usual array-accessing methods to access individual elements and then the dot member operator to access the member functions. For example, the statement. manager[i].putdata( ); th will display the data of the i element of the array manager. This statement requests the object manger[i] to invoke the member function putdata( ); An array of objects is stored inside the memory in the same way as a multi-dimensional array. #include <iostream.h> class employee { char namd[30]; int employee no; public: void getdata(void); void putdata(void); }; void employee : : getdata(void); {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
34
cout << “ Enter name “: “; cin >> name; cout << “Enter employee number”; cin >> eno; } void employee : : putdata(void) { cout << “name : “ << name << “\n”; cout << “age :” << name<< “\n”; } main ( ) { int n; employee manager[10]; for (int i =0; i<n; i++) { cout << “\n Details of employee “ << i+1 << “\n”; manger[i].getdata( ); } cout << “\n”; for(i=0; i<size; i++) { cout << “\n emlpoyee details” << i+1 << “ \n”; manager[i].putdata( ); } } CONSTRUCTORS AND DESTRUCTORS C++ provides a special member function called the constructor which enables an object to initialize itself when it is created. This is known as automatic initialization of objects. It also provides another member function called the destructor that destroys the objects when they are no longer required. CONSTRUCTORS A constructor is a ‘special’ member function whose task is to initialize the objects of its class. It is special because its name is the same as the class name. The constructor is invoked whenever an object of its associated class is created. It is called constructor because it construct the values of data members of the class. A constructor is declared and defined as follows: //class with a constructor class integer { int m, n; public: integer (void); //constructor declared …. …. }; integer : : integer (void) //constructor defined { m = 0; n = 0; } When a class contains a constructor like the one defined above, it is guaranteed that an object created by the class will be initialized automatically. For example, the declaration integer int1; //object int1 created not only creates the objects int1 of the integer but also initializes its data members m and n to zero. There is no need to write any statement to invoke the constructor function (as we do with the normal member functions.) If a ‘normal’ member function is defined for zero initialization, we would need to
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
35
invoke this function for each of the objects separately. This would be very inconvenient, if there are a large number of objects. A constructor that accepts no parameters is called the default constructor. The default constructor for class A is A::A ( ). If no such constructor is defined, then the compiler supplies a default constructor. Therefore a statement such as A a; invokes the default constructor of the compiler to create the object a. The constructor functions have some special characteristics: They should be declared in the public section. They are invoked automatically when the objects are created. They do not have return types, not even void and therefore, they cannot return values. They cannot be inherited, through a derived class can call the base class constructor. Like other C++ functions, they can have default arguments. Constructors cannot be virtual. (Meaning of virtual will be discussed later in Chapter 9.) We cannot refer to their addresses. An object with a constructor (or destructor) cannot be used as a member of a union. They make implicit calls to the operators new and delete when memory allocation is required. Remember, when a constructor is declared for a class, initialization of the class objects becomes mandatory. PARAMETERIZED CONSTRUCTORS The constructor integer ( ), defined above, initializes the data members of all the objects to zero. However, in practice it may be necessary to initialize the various data elements of different objects with different values when they are created. C++ permits us to achieve this objective by passing arguments to the constructor function when the objects are created. The constructors that can take arguments are called parameterized constructors. The constructor integer ( ) may be modified to take arguments as shown below: class integer { int m, n; public: integer (int x, inty); //parameterized constructor .... .... }; integer : : integer(int x, int y) { m = x; n = y; } When a constructor has been parameterized, the object declaration statement such as integer int 1; may out work. We must pass the initial values as arguments to the constructor function when an object is declared. This can be done in two ways: By calling the constructor explicitly. By calling the constructor implicitly. The following declaration illustrates the first method: integer int1 = integer(0, 100); //explicit call This statement creates an integer object int1 and passes the values 0 and 100 to it. The second is implemented as follows: integer int1(0, 100); //implicit call This method, sometimes called the shorthand method, is used very often as it is shorter, looks better and is easy to implement. Remember, when the constructor is parameterized, we must provide appropriate arguments for the constructor. Program 6.1 demonstrates the passing of arguments to the constructor functions.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
36
#include <iostream.h> class integer { int m, n; public: integer (int, int); //constructor declared void display (void) { cout << “ m = “ << m << “\n”; cout << “ n = “ << n << “\n”; } }; integer :: integer (int x, int y) //constructor defined { m = x; n = y; } main ( ) { integer int1(0, 100); //IMPLICIT call integer int2 = integer (25, 75); //EXPLICIT call cout << “\nOBJECT1” << “\n”; int1.display ( ); cout << “\nOBJECT2” << “\n”; int2.display(); }
The constructor functions can also be defined as inline functions. Example: class integer { int m, n; public: integer(int x, int y) //Inline constructor { m = x; y = n; } .... .... }; The parameters of a constructor can be of any type except that of the class to which it belongs. For example, class A { .... .... public: A(A); }; is illegal. However, a constructor can accept a reference to its own class as a parameter. That is, Class A { .... .... public :
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
37
A(A&); }; is valid. In such cases, the constructor is called the copy constructor. MULTIPLE CONSTRUCTORS IN A CLASS So far we have used two kinds of constructors. They are: integer( ); //No arguments integer(int, int); //Two arguments In the first case, the constructor itself supplies the data values and no values are passed by the calling program. In the second case, the function call passes the appropriate values from main ( ), C++ permits us to use both these constructors in the same class. For example we could define a class as follows: Class integer { int m, n; public: integer( ) {m = 0; n = 0;} //constructor 1 integer(int a, int b) {m = a; n = b;) //constructor 2 integer(integer & i) {m = i.m; n = 1.n;) //constructor 3 }; This declares three constructors for an integer object. The first constructor receives no arguments, the second receives two integer arguments and the third receives one integer object as an argument. For example, the declaration integer 11; would automatically invoke the first constructor and set both m and n of I1 to zero. The statement integer 12 (20, 40); would call the second constructor which will initialize the data members m and n of 12 to 20 and 40 respectively. Finally, the statement integer 13(12); would invoke the third constructor which copies the values of 12 into 13. That is, it sets the value of every data element of 13 to the value of the corresponding data element of 12. As mentioned earlier, such a constructor is called the copy constructor. We learned in Chapter 4 that the process of sharing the same name by two or more functions is referred to as function overloading. Similarly, when more than one constructor function is defined in a class, we say that the constructor is overloaded. Program shows the use of overloaded constructors. #include <iostream.h> class complex { float x, y; public : complex() { } //constructor no arg complex(float a) {x = y = a;} //constructor â&#x20AC;&#x201C;one arg complex(float real, float imag) //constructor-two args {x = real; y = imag; } friend complex sum(complex, complex); friend void show (complex); }; complex sum (complex cl, complex c2) //friend { complex c3; c3.x = c1.x + c2.x; c3.y = c1.y + c2.y; return (c3); } void show (complex c) //friend
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
38
{ cout << c.x << “ + j” << c.y < “\n”; } main ( ) { complex A (2.7, 3.5); complex B (1.6); complex c; C = sum (A, B); cout << “A = “; show (A); cout << “B = “; show (B); cout << “C = “; show (C);
//define & initialize //define & initialize //define //sum() is a friend //show () is also friend
// Another way to give initial values (second method) complex P, Q, R; P = complex (2.5, 3.9); //initialize P Q = complex (1.6, 2.5); //initialize Q R = sum (P, Q); cout << “\n”; cout << “P = “; show (P); cout << “Q = “; show (Q); cout << “R = “; show (R);
//define P, Q and R
} There are three constructors in the class complex. The first, which takes no arguments, is used to create objects which are not initialized. The second, which takes one argument, is used to create objects and initialize them. The third constructor, which takes two arguments, is also used to create objects and initialize them to specific values. Note that the second method of initializing values looks better. Let us look at the first constructor again. complex ( ) { } It contains the empty body and does not do anything. We just stated that this is used to create objects without any initial values. Remember, we have defined objects in the earlier examples without using such a constructor. Why do we need this constructor now? As pointed out earlier, C++ compiler has an implicit constructor which creates objects, even though it was not defined in the class. This works fine as long as we do not use any other constructors in the class. However, once we define a constructor, we must also define the “do-nothing” implicit constructor. This constructor will not do anything and is defined just to satisfy the compiler. CONSTRUCTORS WITH DEFAULT ARGUMENTS It is possible to define constructors with default arguments. For example, the constructor complex ( ) can be declared as follows: complex(float real, float imag = 0); The default value of the argument imag is zero. Then, the statement complex C(5.0); assigns the value 5.0 to the real variable and 0.0 to imag (by default). However, the statement complex C(2.0, 3.0); assigns 2.0 to real and 3.0 to imag. The actual parameter, when specified, overrides the default value. As pointed out earlier, the missing arguments must be the trailing ones. It is important to distinguish between the default constructor A::A( ) and the default argument constructor A::A(int = 0). The default argument constructor can be called with either one argument or no arguments. When called with no arguments, it becomes a default constructor. When both these forms are used in a class, it causes ambiguity for a statement such as A a; The ambiguity is whether to ‘call’ A::A( ) or A::A(int =.0).
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
39
DYNAMIC INITIALIZATION OF OBJECTS Class objects can be initialized dynamically too. That is, the initial value of an object may be provided during run time. One advantage of dynamic initialization of that we can provide various initialization formats, using overloaded constructors. This provides the flexibility of using different format of data at run time depending upon the situation. Consider the long term deposit schemes working in the commercial banks. The banks provide different interest rates for different schemes as well as for different periods of investment. Program 6.3 illustrates how to use the class variables for holding account details and how to construct there variables at run time using dynamic initialization. #include <iostream.h> class Fixed_deposit { long int P_amount; //Principal amount int Years; //Period of investment float Rate; //Interest rate float R_value; //Return value of amount public: Fixed_deposit() { } Fixed_deposit(long int p, int y, float r = 0.12); Fixed_deposit(long int p, int y, int r); void display(void); }; Fixed_deposit :: Fixed_deposit(long int p, int y, float r) { P_amount = p; Years = y; Rate = r; R_value = P_amount; for (int i = 1, I <= y; i++) R_value = R_value * (1.0 + r); } Fixed_deposit :: Fixed_deposit(long int p, int y, float r) { P_amount = p; Years = y; Rate = r; R_value = P_amount; for (int i = 1, I <= y; i++) R_value = R_value * (1.0 + float (r)/100); } void Fixed_deposit :: display (void) { cout << “\n” << “Principal Amount = “ << P_amount << “\n” << “Return value = “ << R_value << “\n”; } main( ) { Fixed_deposit FD1, FD2, FD3; //deposits created long int p; //principal amount int y; //investment period, years float r; //interest rate, decimal form int R; //interest rate, percent form cout << “Enter amount, period, interest rate(in percent)”<<”\n; cin >> p >> y >> R; FD1 = Fixed_deposit (p,y,R); cout.<< “Enter, period, interest rate(decimal form)” <<”\r cin >> p >> y >> r; FD2 = Fixed_deposit(p,y,r);
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
40
cout << “Enter amount and period” << “\n”; cin >> p >> y; FD3 = Fixed_deposit (p,y) cout << “\nDeposit 1”; FD1.display (); cout << “\Deposit 2”; FD2.display (); cout << “\Deposit 3”; FD3.display (); } Since the constructors are overloaded with the appropriate parameters, the one that matches the input values is invoked. For example, the second constructor is invoked for the forms (1) and (3), and the third is invoked for the form (2). Note that, for form (3), the constructor with default argument is used. Since input to the third parameter is missing, it uses the default value for r. COPY CONSTRUCTOR The copy constructor is used as given below, integer(integer & i); As stated earlier, a copy constructor is used to declare and initialize an object from another object. For example, the statement integer 12(I1); would define the object 12 and at the same time initialize it to the values of I1. Another form of this statement is integer 12 = I1; The process of initializing through a copy constructor is known as copy initialization. Remember, the statement 12 = I1; will not invoke the copy constructor. However, if I1 and 12 are objects, this statement is legal and simply assigns the values of I1 to 12, member-by-member. This is the task of the overloaded assignment operator (=). We shall see more about this later. A copy constructor takes a reference to an object of the same class as itself as an argument. Let us consider a simple example of constructing and using a coy constructor as show in Program 6.4 #include <iostream.h> class code { int id; public: code() { } //constructor code(int a) {id = a;} //constructor again code (code & x) //copy constructor { //copy in the value id = x.id; } void display (void) { cout << id; } }; main( ) { code A(100); //object A is created an initialized code B(A); //copy constructor called code C = A; //copy constructor called again code D; //D is created, not initialized D = A; //copy constructor not called cout << “\n id of A: “; A.display(); cout << “\n id of B: “; B.display();
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
41
cout << “\n id of C: “; C.display(); cout << “\n id of D: “; D.display(); } Note that a reference variable has been used in the argument to the copy constructor. We cannot pass the argument by value to a copy constructor. When no copy constructor is defined, the compiler supplies its own copy constructor.
DYNAMIC CONSTRUCTORS The constructors can also be used to allocate memory while creating objects. This will enable the system to allocate the right amount of memory for each object when the objects are not of the same size, thus resulting in the saving of memory. Allocation of memory to objects at the time of their construction is known as dynamic construction of objects. The memory is allocated with the help of the new operator. Program 6.5 shows the use of new in constructors that are used to construct strings in objects. #include <iostream.h> #include <string.h> class string { char *name; int length; public: string() { length = 0; name = new char (length +1); } string (char * s) { length = strlen(s); name = new char[length + 1]; strcpy (name, s); } void display (void) {cout <<name <<”\n”} void join (string & a, string & b); }; void string :: join (string & a, string & b) { length = a.length + b.length; delete name; name = new char [length +1]; strcpy (name, a.name); strcat (name, b.name); }; main () { char *first = “joseph “; string name1(first),name2(“Louis “), name3(“Lagrange”,s1,s2; s1.join (name1, name2); name1.display(); name2.display(); name3.display(); s1.display(); s2.display(); }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
42
Program uses two constructors. The first is an empty constructor the allows us to declare an array of strings. The second constructor initializes the length of the string, allocates necessary space for the string to be stored and creates the string itself. Note that one additional character space is allocated to hold the end-of-string character ‘\O’. The member function joint( ) concatenates two strings. It estimates the combined length of the strings to be joined, allocates memory for the combined string and then creates the same using the string functions strcpy ( ) and strcat( ). Note that in the function join( ), length and name are members of the object that calls the function, while a.length and a.name are members of the argument object a. The main ( ) function program concatenates three strings into one string.
CONSTRUCTING TWO-DIMENSIONAL ARRAYS We can construct matrix variables using the class type objects. The example in Program illustrates how to construct a matrix of size m x n. #include <iostream.h> class matrix { int **p; //pointer to matrix int d1, d2; //dimensions public: matrix(int x, int y); void get_element(int I, int j, int value) {p[i] [j]=value; } int & put_element (int I, int j) {return p[i] [j]; } }; matrix :: matrix(int x, int y) { d1 = x; d2 = y; p = new int *[d1]; //creates an arry pointer for (int i = 0; i <d1; i++) p[i] = new int[d2]; //creates space for each row } main() { int m, n; cout < “Enter size of matrix: “; cin >> m >> n; matrix A(m, n); //matrix object A constructed cout << “Enter matrix elements row by row \n”; int I, j, value: for (I = 0; i <m; i++) for (j = 0; j < n; j++) { cin >> value; A.get_element (i,j,value); } cout << “\n”; cout << A.put_element(1,2); }; DESTRUCTORS A destructor, as the name implies, is used to destroy the objects that have been created by a constructor. Like a constructor, the destructor is a member function whose name is the same as the class name but is preceded by a tilde. For example, the destructor for the class integer can be defined as shown below: ~integer( ){ } A destructor never takes any argument nor does it return any value. It will be invoked implicitly by the compiler upon exit from the program (or block or function as the case may be) to
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
43
clean up storage that is no longer accessible. It is a good practice to declare destructors in a program since it releases memory space for future use. Whenever new is used to allocate memory in the constructors, we should use delete to free that memory. For example, the destructor for the matrix class discussed above may be defined as follows: matrix :: matrix ( ) { for(int I = 0; I < d1; i++) delete p[i]; delete p; } This is required because when the pointers to objects go out of scope, a destructor is not called implicitly. The example below illustrates the destructor has been invoked implicitly by the compiler. #include <iostream.h> int count = 0; { public: alpha() { count++; cpit << “\nNo.of object created “ << count; } ~alpha () { cout << “\nNO.of object destroyed “ << count; count--; } }; main() { cout << “\n\nENTER MAIN\n”; alpha A1, A2, A3, A4; { cout << “\n\nENTER BLOCK1\n”; } { cout << “\n\nENTER BLOCK2\n”; alpha A6; } cout << “\n\nRE-ENTER MAIN\n”; }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
44
UNIT II OPERATOR OVERLOADING AND TYPE CONVERSIONS Operator overloading is one of the many exciting features of C++ language. The mechanism of giving a special meaning to an operator is known as operator overloading. Operator overloading provides a flexible option for the creation of new definitions for most of the C++ operators. One can almost create a new language of our own by the creative use of the function and operator overloading techniques. We can overload (give additional meaning to) all the C++ operators except the following: Class member access operators (., .*). Scope resolution operator (::). Size operator (sizeof). Conditional operator (?:). The excluded operators are very few when compared to the large number of operators which qualify for the operator overloading definition. Although the semantics of an operator can be extended, we cannot change its syntax, the grammatical rules that govern its use such as the number of operands, precedence and associativity. For example, the multiplication operator will enjoy higher precedence than the addition operator. When an operator is overloaded, its original meaning is not lost. For instance, the operator +, which has been overloaded to add two vectors, can still be used to add two integers. DEFINING OPERATOR OVERLOADING To define an additional task to an operator, we must specify what it means in relation to the class to which the operator is applied. This is done with the help of a special function, called operator function, which describes the task. The general form of an operator function is: Syntax:
returntype classname :: operator op (arg-list) { Function body //task defined } where returntype is the type of value returned by the specified operation and op is the operator being overloaded. The op is preceded by the keyword operator, operator op is the function name. Operator functions must be either member functions (non-static) or friend functions. A basic difference between them is that a friend function will have only one argument for unary operators and two for binary operators, while a member function has no arguments for unary operators and only one for binary operators. This is because the object used to invoke the member function is passed implicitly and therefore is available for the member function. This is not the case with friend functions. Arguments may be passed either by value or by reference. Operator functions are declared in the class using prototypes as follows: complex operator + (vector); //vector addition complex operator – ( ) //unary minus friend vector operator + (vector, vector); //vector addition complex and vector is a data type of class and may represent both magnitude and direction (as in physics and engineering) or a series of points called elements (as in mathematics). The process of overloading involves the following steps: 1. First, create a class that defines the data type that is to be used in the overloading operations. 2. Declare the operator function operator op ( ) in the public part of the class. It may be either a member function or a friend function. 3. Define the operator function to implement the required operations. Overloaded operator functions can be invoked by expressions such as OP x or x OP for unary operators and x op y for binary operators. OP x (or x op) would be interpreted as operator op (x)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
45
for friend functions. Similarly, the expression x op y would be interpreted as either x.operator op(y) in case of member functions, or operator op (x, y) in case of friend functions. When both the forms are declared, standard argument matching is applied to resolve any ambiguity. OVERLOADING UNARY OPERATORS A minus operator, when used as a unary, takes just one operand. This operator changes the sign of an operand when applied to a basic data item. The unary minus when applied to an object should change the sign of each of its data items. #include <iostream.h> class sample { int x; public: void getdata (int a); void display (void); void operator-(); //overload unary minus }; void sample :: getdata (int a) { x = a; } void sample :: display (void) { cout << x ; } void sample :: operator-() //Defining operator-() { x = -x; } main () { sample s; s.getdata(10); cout << “S: “; s.display(); -s; //activates oerator-() cout << “S : “; s.display(); } OVERLOADING BINARY OPERATORS The same mechanism can be used to overload a binary operator. Overloading of binary operators can be implemented by adding two complex numbers using a friend function. A statement like C = sum(A, B); //functional notation was used. The functional notation can be replaced by a natural-looking expression C = A + B; // arithmetic notation by overloading the + operator using an operator+( ) function. The Program 7.2 illustrates how this is accomplished. #include <iostream.h> class complex { float x; float y; public: complex( ) { } //real part
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING complex(float real, float imag) {x = real; y = imag;] complex operator+(complex); void display (void);
46 //imaginary part
}; complex complex :: operator+complex c) { complex temp; temp.x = x + c.x; temp.y = y + c.y; } void complex :: display(void) { cout << x << “ + j” << y << “\n”; } main( ) { complex C1, C2, C3; C1 = complex (2.5, 3.5); C2 = complex (1.6, 2.7)’ C3 = C1 + C2; cout << “C1 = “; C1.display( ); cout << “C2 = “; C2.display( ); cout << “C3 = “l C3.display( ); } OVERLOADING BINARY OPERATORS USING FRIENDS As stated earlier, friend functions may be used in the place of member functions for overloading a binary operator. The only difference being that a friend function requires two arguments to be explicitly passed to it while a member function requires only one. The complex number program discussed in the previous section can be modified using a friend operator function as follows: 1. Replace the member function declaration by the friend function declaration. friend complex operator+(complex, complex); 2. Redefine the operator function as follows: complex operator+(complex a, complex b) { return complex((a.x + b.x), (a.y + b.y)); } In this case, the statement C3 = C1 + C2; is equivalent to C3 = operator+(C1, C2); In most cases, we will get the same results by the use of either a friend function or a member function. Why is then an alternative is made available?. There are certain situations where we would like to use a friend function rather than a member function. For instance consider a situation where we need to use two different type of operands for a binary operator, say, one an object and another a built-in type data as shown below: A = B + 2; (or A = B * 2;) We are A and B are objects of the same class. This will work for a member function but the statement A = 2 + B; (or A = 2 * B;) will not work. This is because the left-hand operand which is responsible for invoking the member function should be an object of the same class. However, a friend function allows both the approaches. How? It may be recalled that an object need not be used to invoke a friend function but can be passed as an argument. Thus, we can use a friend function with a built-in type data as the left-hand operand and an object as the right-hand operand. Program 7.3 illustrates this using scalar multiplication of a vector. It also shows how to overload the input and output operators >> and <<. #include <iostream.h>
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING const size = 3; class vector { int v[size]; public: vector( ); vector (int * x); friend vector operator * (int a, vector b); friend vector operator * (vector b, int a); friend istream & operator >> (istream &, vector &); friend ostream & operator << (ostream &, vector &); }; vector :: vector () { for (int i = 0; i < size; i++) v[i] = 0; } vector :: vector (int * x) { for (int i = 0; i < size; i++) v[i] = x[i]; } vector operator *(int a, vector b) { vector c; for (int i = 0; i < size; i++) c.v[i] = a * b.v[i]; return c; } vector operator *(vector b, int a) { vector c; for (int i = 0; i < size; i++) c.v[i] = b.v[i] * a; return c; } istream & operator >> (istream & din, vector & b) { for (int i = 0; i < size; i++) din >>> b.v[i]; return (din); } ostream & operator >> (ostream & dout, vector & b) { dout << “(“ << b.v[0]; for (int i = 1; i < size; i++) dout << “, “ < b.v [i]; dout << “)”; return (dout); } int x[size] = [2,4,6]; main ( ) { vector m; //invokes constructor 1 vector n = x; //invokes construct 2 cout << “Enter elements of vector m “ << “\n”; cin >> m; // invokes operator >> () cout << “\n”; cout << “m =” << m << “\n”; //invokes operator <<() vector p, q;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
47
OBJECT ORIENTED PROGRAMMING p = 2 * m; q = n * 2;
48
//invokes friend 1 //invokes friend 2
cout << “\n”; cout << “p = “ << p << “\n”; cout << “q = “ << q << “\n”;
//invokes operator<<()
} MANIPULATION OF STRINGS USING OPERATORS ANSI C implements strings using character arrays, pointers and string functions. There are no operators for manipulating the strings. One of the main drawbacks of string manipulations in C is that whenever a string is to be copied, the programmer must first determine its length and allocate the required amount of memory. Although these limitations exist in C++ as well, it permits us to create out own definitions of operators that can be used to manipulate the strings very much similar to the decimal numbers. For example, we shall be able to use statements like string3 = string1 + string2; if(string1>=string2) string = string1; Strings can be defined as class objects which can be then manipulated like the built-in types. Since the strings vary greatly in size, we use new to allocate memory for each string and a pointer variable to point to the string array. Thus, we must create string objects that can hold these two pieces of information, namely, length and location which are necessary for string manipulations. A typical string class will look as follows; class string { char *p; //pointer to string int len; //length of string public: .... //member functions .... //to initialize and .... //manipulate strings }; We shall consider an example program to illustrate the application of overloaded operators to strings. The example shown in Program 7.4 overloads two operators, + and <= just to show how they are implemented. This can be extended to cover other operators as well. #include <string.h> #include <iostream.h> class string { char *p; int len; public: string() (len = 0; p = 0;1 //create null string string(const char * s); //create string from array s string(const string & s); //copy constructor *string (){delete p;} //destructor friend string operator+(const string & s, const string &t); friend int operator<={const string & s, const string &t); friend void show(const string s); }; string :: string (const char * s) { len = strlen(s); p = new char(len + 1); strcpy(p,s); } string :: string(const string & s) { len = s.len; p = new char (len + 1); strcpy(p, s.p);
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
49
} string operator + (const string & s, const string & t) { string temp; temp.len = s.len + t.len; temp.p = new char[temp.len + 1]; strcpy (temp.p,s.p); strcat (temp.p,t.p); return (temp); } int operator<=(const string & s. const string & t) { int m = strlen (s.p); int n = strlen (t.p); if(m <= n) return (1); else return (o); } void show (const string s) { cout << s.p; } main () { string s1 = “New“; string s2 = “York“; string s3 = “Delhi“; string t1, t2, t3, t4; t1 = s1; t2 = s2; t3 = s1+s2; t4 = s1 + s3; cout << “\nt1 = “; show(t1); cout << “\nt2 = “; show(t2); cout << “\nt“; cout << “\nt3 = “; show(t3); cout << “\nt4 = “; show(t4); cout << “\n\n”; if(t3 <= t4) { show(t3); cout << “smaller than”; show(t4); cout << “\n”; }
else { show(t4); cout << “ smaller than ”; show(t3); cout << “\n”; } } RULES FOR OVERLOADING OPERATORS Although it looks simple to redefine the operators, there are certain restrictions and limitations in overloading them. Some of them are listed below: 1. Only existing operators can be overloaded. New operators cannot created. 2. The overloaded operator must have a least one operand that is of user-defined type.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
50
3. We cannot change the basic meaning of an operator. That is, we cannot redefine the plus(+) operator to subtract one value from the other. 4. Overloaded operators follow the syntax rules of the original operators. The cannot be overridden. 5. There are some operators that cannot be overloaded. (See Table 7.1) 6. We cannot use friend functions to overload certain operators. (See Table 7.2) However, member functions can be used to overload them. 7. Unary operators, overloaded by means of a member functions, take no explicit arguments and return no explicit values. But, those overloaded by means of a friend function take one reference argument (the object of the relevant class). 8. Binary operators overloaded through a member function take one explicit argument and those which are overloaded through a friend function take two explicit arguments. 9. When using binary operators overloaded through a member function, the left-hand operand must be an object of the relevant class. 10. Binary arithmetic operators such as +, - , * , and / must explicitly return a value. They must not attempt to change their own arguments. TYPE OF CONVERSIONS We know that when constants and variables of different types are mixed in an expression, C applies automatic type conversion to the operands as per certain rules. Similarly, an assignment operation also causes the automatic type conversion. The type of data to the right of an assignment operator is automatically converted to the type of the variable on the left. For example, the statements int m; float x = 3.14159; m = x; convert x to an integer before its value is assigned to m. Thus, the fractional part is truncated. The type conversions are automatic as long as data types involved are built-in types. What happens when they are user-defined data types? Consider the following statement that adds two objects and then assigns the result to a third object. V3 = V1 + V2; //V1, V2 and V3 are class type objects When the objects are of the same class type, the operations of addition and assignment are carried out smoothly and the compiler does not make any complaints. We have seen, in the case of class objects, the values of all the data members of the right-hand object are simply copied into the corresponding members of the object on the left-hand. Since the user-defined data types are designed by us to suit our requirements, the compiler does not support automatic type conversions for such data types. We must, therefore, design the conversion routines by ourselves, if such operations are required. Three types of situations might arise in the data conversion between uncompatible types: 1. Conversion from built-in type to class type. 2. Conversion from class type to built-in type. 3. Conversion from one class type to another class type. The conversion from basic type to class type is easy to accomplish. It may be recalled that the use of constructors was illustrated in a number of examples to initialize objects. For example, a constructor was used to build a vector object from an int type array. Similarly, we used another constructor to build a string type object from a chart* type variable. These are all examples where constructors perform a defacto type conversion from the argument’s type to the constructor’s class type. Consider the following constructor: string :: string(char*a) { length = strlen(a); P = new char[length + 1]; strcpy (P, a); } The constructor builds a string type object from a char* type variable a. The variables length and P are data members of the class string. Once this constructor has been defined in the string class, it can be used for conversion from char* type to string type. Example: string s1, s2; char* name1 = *IBM PC”;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
51
char* name2 = “Apple Computers”; s1 = string(name1); S2 = name2; The statement first converts name1 from char* type to string type and then assigns the string type values to the object s1. The statement s1 = string(name1); also does the same job by invoking the constructor implicitly. s2 = name2; Class to Basic Type The constructors did a fine job in type conversion from a basic to class type. What about the conversion from a class to basic type? The constructor functions do not support this operation, Luckily, C++ allows us to define a overloaded casting operator that could be used to convert a class type data to a basic type. The general form of an overloaded casting operator function, usually referred to as a conversion function, is:
operator typename( ) { .... . . . . (Function statements) .... This function converts a class type data to typename. For example, the operator double() converts a class object to type} double, the operator int ( ) converts a class type object to type int, and so on. Consider the following conversion function: Vector :: operator double( ) { double sum = 0; for(int i = 0; i < size; i ++) sum = sum + v[i] *v[i]; return sqrt(sum); } This function converts a vector to the corresponding scalar magnitude. Recall that the magnitude of a vector is given by the square root of the sum of the squares of its components. The operator double( ) can be used as follows: double length = double(V1); or double length = V1; where V1 is an object of type vector. Both the statements have exactly the same effect. When the compiler encounters a statement that requires the conversion of a class type to a basic type, it quietly calls the casting operator function to do the job. The casting operator function should satisfy the following conditions: It must be a class member. It must not specify a return type. It must not have any arguments. Since it is a member function, it is invoked by the object and therefore, the values used for conversion inside the function belong to the object that invoked the function. This means that the function does not need an argument. One Class to Another Class Type We have just seen data conversion techniques from a basic to class type and a class to basic type. But there are situations where we would like to convert one class type data to another class type. Example. objX = objY; //objects of different types ObjX is an object of class X and objY is an object of class Y. The class Y type data is converted to the class X type data and the converted value is assigned to the objX. Since the conversion takes place from class Y to class X, Y is known as the source class and X is known as the destination class.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
52
INHERITANCE: EXTENDING CLASSES Reusability is yet another important feature of OOP. It is always nice if we could reuse something that already exists rather than trying to create the same all over again. It would not only save time and money but also reduce frustration and increase reliability. For instance, the reuse of a class that has already been tested, debugged and used many times can save us the effort of developing and testing the same again. Fortunately, C++ strongly supports the concept of reusability. The C++ classes can be reused in several ways. Once a class has been written and tested, it can be adapted by other programmers to suit their requirements. This is basically done by creating new classes, reusing the properties of the existing ones. The mechanism of deriving a new class from an old one is called inheritance (or derivation). The old class is referred to as the base class and the new one is called the derived class. The derived class inherits some or all of the traits from the base class. A class can also A inherit properties from more than one class or from more than one level. A derived class with only one base class is called single inheritance and one with several base classes is called multiple inheritance. On the other hand, the traits of one class may be inherited by more than one class. This process is known as hierarchical inheritance. The mechanism of deriving a class from another B â&#x20AC;&#x2DC;derived classâ&#x20AC;&#x2122; is known as multilevel inheritance The direction of arrow indicates the direction of inheritance a) Single inheritance A
B
A
B
C
D
C b) Multiple inheritance A
b) Hierarchical inheritance A
B B C DEFINING DERIVED CLASSES A derived class is defined by specifying its relationship with the base class in addition to its own details. The general form of defining a derived class is: C
D
class derived-class-name: Visiblity-mode base-class-name e) Hybrid inheritance { d) Multilevel inheritance . . . . // . . . . // members of derived class . . . . // }; The colon indicates that the derived-class-name is derived from the base-class-name. The visibility mode is optional and, if present, may be either private or public. The default visibility-mode is private. Visibility mode specifies whether the features of the base class are privately derived or publicly derived. Example: class ABC : private XYZ //private derivation { members of ABC }; class ABC : public ZYZ // public derivation {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
53
members of ABC }; class ABC : XYZ //private derivation by default { members of ABC }; When a base class is privately inherited by a derived class. ‘public members’ of the base class become ‘private members’ of the derived class and therefore the public members of the base class can only be accessed by the member functions of the derived class. They are inaccessible to the objects of the derived class. Remember, a public member of a class can be accessed by its own objects using the dot operator. The result is that no member of the base class is accessible to the objects of the derived class. On the other hand, when the base class is publicly inherited, ‘public members’ of the base class become ‘public members’ of the derived class and therefore they are accessible to the objects of the derived class. In both the cases, the private members are not inherited, and therefore, the private members of a base class will never become the members of its derived class. In inheritance, some of the base class data elements and member functions are ‘inherited’ into the derived class. We can add our own data and member functions and thus extend the functionality of the base class. Inheritance, when used to modify and extend the capabilities of the existing classes, becomes a very powerful tool for incremental program development. SINGLE INHERITANCE Let us consider a simple example to illustrate inheritance. Program shows a base class B and a derived class D. The class B contains one private data member, one public data member, and three public member functions. The class D contains one private data member and two public member functions. #include <iostream.h> class B { int a; //private; not inheritable public: int b; //public; ready for inheritance void get_ab(); int get_a(void); void show_a(void); }; class D: public B //public derivation { int c; public: void mul(void); void display(void); }; //............................FUNCTIONS DEFINED............ void B:: get_ab(void) { a = 5; b = 10; } int B :: get_a() { return a; } void D :: mul () { c = b * get_a(); } void D :: display() { cout << “a = “ << get_a() << “\n”; cout << “b = “ << b << “\n”; cout << “c = “ << c << “\n\n”; } main ()
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
54
{ D d; d.get_ab(); d.mul(); d.show_a(); d.display(); d.b = 20; d.mul(); d.display(); } MAKING A PRIVATE MEMBER INHERITABLE We have just seen how to increase the capabilities of an existing class without modifying it. We have also seen that a private member of a base class cannot be inherited and therefore it is not available for the derived class directly. What do we do if the private data needs to be inherited by a derived class? This can be accomplished by modifying the visibility limit of the private member by making it public. This would make it accessible to all the other functions of the program, thus eliminate the advantage of data hiding. C++ provides a third visibility modifier, protected, which serve a limited purpose in inheritance. A member declared as protected is accessible by the member functions within its class and any class immediately derived from it. It cannot be accessed by the functions outside these two classes. A class can now use all the three visibility modes as illustrated below: class alpha { private: //optional .... //Visibile to member functions .... //within its class protected: .... ....
//visible to member functions //of its own and derived class
public: .... //visible to all functions .... //n the program When a protected member is inherited in public mode, it becomes protected in the derived class too, and therefore is accessible by the member functions of the derived class. It is also ready for further inheritance. A protected member, inherited in the private mode derivation, becomes private in the derived class. Although it is available to the member functions of the derived class, it is not available for further inheritance (since private members cannot be inherited). Table 8.1 summarizes how the visibility of members undergo modifications when they are inherited. Figure 8.4 is the pictorial representation for the two levels of derivation. Derived class visibility
Bas class visibility
Public derivation
Private derivation
Private
Not inherited
Not inherited
Protected
Protected
Private
Public
Public
Private
The keywords private, protected, and public may appear in any order and in any number of times in the declaration of a class. For example, class beta { protected:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
55
... public: ... private: ... public: ... }; is a valid class definition. However, the normal practice is to use them as follows: class beta { . . . . //private by default .... protected: ... public: ...
Class B Not inheritable X
Private
X Not inheritable
Protected Public
Class D1 : public B
Class D2 : private B
Private
Private
Protected
Protected
Public
Public
Class X : public D1 : public D2
Private Protected Public Effect in inheritance on the visibility of members Now let us review the access control to the private and protected members of a class. What are the various functions that can have access to these members? They could be:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
56
class X friend class Y;
class Y
private fx1
fy1
data class Y protected
fx2
fy2
data
friend of X
.
fz1
function 1 friend of X
fz2
Inherited from X Access mechanism in classes 1. 2. 3.
A function that is a friend of the class. A member function of a class that is a friend of the class. A member function of a derived class.
While the friend functions and the member functions of a friend class can have direct access to both the private and protected data, the member functions of a derived class can directly access only the protected data. However, they can access the private data through the member functions of the base class. Figure 8.5 illustrates how the access control mechanism works in various situations. MULTILEVEL INHERITANCE The class A serves as a base class for the derived class B which in turn serves as a base class for the derived class C. The class B is known as intermediate base class since it provides a link for the inheritance between A and C. The chain ABC is known as inheritance path.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
Base class
A
Intermediate base class
A
57
Grandfather
Father
Multilevel inheritance A derived class with multilevel inheritance is declared as follows: Derived class Child A class A{..........}; //Base class class B: public A {........}; //B derived from A class C: public B {........}; //C derived from B This process can be extended to any number of levels. Let us consider a simple example. Assume that the test results of a batch of students are stored in three different class. Class student stores the roll-number, class test stores the marks obtained in two subjects and class result contains the total marks obtained in the test. The class result can inherit the details of the marks obtained in the test and the roll-number of students through multilevel inheritance. Example:
class student { protected: int roll_number; public: void get_number(int); void put_number(void); }; void student :: get_number(int a) { roll_number = a; } void student :: put_number( ) { cout << “Roll Number:” << roll_number << “\n”; } class test : public student //First level derivation { protected: float sub1; float sub2; public: void get_marks(float x, float y) void put_marks(void); } sub1 = x; sub2 = y; } void test :: put_marks( ) { cout << “Marks in SUB1 = “ << sub1 << “\n”; cout << “Marks in SUB2 = “ << sub2 << “\n”;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
58
} class result : public test //Second level derivation } float total; // private by default public: void display (void); }; The class result, after inheritance from ‘grandfather’ through ‘father’, would contain the following members: private: float total; //own member protected: int roll_number; //inherited from student via test float sub1; //inherited from test float sub2; //inherited from test public: void get_number(int); //from student via test void put_number (void); //from student via test void get_marks(float, float); //from test void put_marks(void); //from test void display(void); //own member The inherited functions put_number( ) and put_marks( ) can be used in the definition of display( ) function: void result :: display (void) { total = sub1 + sub2; put_number( ); put_marks( ); cout << “Total = “ << total << “\n”; } Here is a simple main ( ) program: main( ) { result student1;
//student1 created
student1.get_number(111); student.get_marks(75.0, 59.5); student1.display( ); } This will display the result of student1. The complete program is shown in Program 8.3. #include <isotream.h> class student { protected: int roll_number; public: void get_number(int); void put_number(void); };
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
59
void student :: get_number(int a) { roll_number = a; } void student :: put_number() { cout << “Roll Number: “ << roll_number << “\n”;} class test : public student //FIRST LEVEL DERIVATION { protected: float sub1; float sub2; public: void get_marks(float, float); void put_marks(void); }; void test :: get_marks(floa x, float y) { sub1 = x; sub2 = y; } void test :: put_marks ( ) { cout << “Marks in SUB1 = “ << sub1 << “\n”; cout << “Marks in SUB2 = “ << sub2 << “\n”; } class result : public test //SECOND LEVEL DERIVATION { float total ; //Private by default public: void display (void); }; void result :: display (void) { total = sub1 + sub2; put_number( ); put_marks ( ); cout << “Total = “ << total << “\n”; } main ( ) { result student 1; //student1 created student1.get_number(111); student1.get_marks(75.0, 59.5); student1.display( ); } MULTIPLE INHERITANCE A class can inherit the attributes of two or more classes .This is known as multiple inheritance. Multiple inheritance allows us to combine the features of several existing
B-1
B-2
....
B-n
Multiple inheritance D
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
60
classes as a starting point for defining new classes. It is like child inheriting the physical features of one parent and the intelligence of another. class D : visibility B â&#x20AC;&#x201C; 1, visibility B-2, . . . . { ..... . . . . . (Body of D) ..... }; where, visibility may be either public or private. Example: class P : public M, public N { public: void display(void); }; Class M and N have been specified as follows: class M { protected; int m; public: void get_m(int); }; void M :: get_m(int x) { m = x; } class N { protected: int n; public: void get_n(int); }; void N :: get_n(int y) { n = y; }
The base classes are separated by commas
The derived class P, as declared above, would, in effect, contain all the members of M and N in addition to its own members as shown below: class P { protected: int m; int n; public:
};
void get_m(int); void get_n(int); void display(void);
//from M //from N
//from M //from N //own member
The member function display( ) can be defined as follows:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
61
void P :: display(void) { cout << “m =” << m << “\n”; cout << “n =” << n << “\n”; cout << “m*n =” << m*n << “\n”; } The main( ) function which provides the user-interface may be written as follows: main( ) { Pp; p.get_m(10); p.get_n(20); p.display( ); } Example: #include <isotream.h> class M { protected: int m; public: void get_m(int); }; class N protected: int n; public: void get_n(int); }; class P : public M, public N { public: void display(void); }; void M :: get_m(int x) { m = x; } void M :: get_n(int y) { n = y; } void P :: display(void) { cout << “m = “ << m << “\n”;} cout << “n = “ << n << “\n”;} cout << “m*n = “ << m*n << “\n”;} } main() { P p; p.get_m(10); p.get_n(20); p.display(); } HIERARCHICAL INHERITANCE We have discussed so far how inheritance can be used to modify a class when it did not satisfy the requirements of a particular problem on hand. Additional members are added through inheritance to extend the capabilities of a class. Another interesting application of inheritance is to
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
62
use it as a support to the hierarchical design of a program. Many programming problems can be cast into a hierarchy where certain features of one level are shared by many others below that level. In C++, such problems can be easily converted into class hierarchies. The base class will include all the features that are common to the subclasses. A subclass can be constructed by inheriting the properties of the base class. A subclass can serve as a base class for the lower level classes and so on.
HYBRID INHERITANCE There could be situations where we need to apply two or more types of inheritance to design a program. For instance, consider the case of processing the student results discussed in sections 8.5. Assume that we have to give weightage for sports before finalising the result. The weightage for sports is stored in a separate class called sports. The new inheritance relationship between the various classes would be as shown in Figure. student
test
sports
result Multilevel, multiple inheritance The sports class might look like: class sports { protected: float score; public: void get_score(float); void put_score(void); }; The result will have both the multilevel and multiple inheritances and its declaration would be as follows: class results : public test, public sports { .... .... }; where test itself is a derived class from student. That is class test : public student { .... .... }; Example #include <iostream.h>
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING class student { protected: int roll_number; public: void get_number(int a) { roll_number = a; } void put_number (void) { cout << “Roll No: “ << roll_number << “\n”; } }; class test : public student { protected: float part1, part2; public: void get_marks(float x, float y) { part1 = x; part2 = y; } void put_marks(void) { cout << “Marks obtained: “ << “\n”; << “part1 = “ << part1 << “\n” << “part2 = “ << part2 << “\n” } }; class sports } protected: float score; public: void get_score(float s) { score = s; } void put_score(void) { cout << “Sports wt: “ << score << “\n\n”; } }; class result : public test, public sports { float total; public: void display(void); }; total = part1 + part2 + score; put_number(); put_marms(); put_score(); cout << “Total Score: “ << total << “\n”; } main() { result student_1; student_1.get_number(1234); student_1.get_marks(27.5, 33.0); student_1.get_score (6.0); student_1.display(); }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
63
OBJECT ORIENTED PROGRAMMING
64
VIRTUAL BASE CLASSES: We have just discussed a situation which would require the use of both the multiple and multilevel inheritance. Consider a situation where all the three kinds of inheritance, namely, multilevel, multiple and hierarchical inheritance, are involved. The ‘child’ has two direct base classes ‘parent1’ and ‘parent2’ which themselves have a common base class ‘grandparent’, The ‘child’ inherits the traits of ‘grandparent’ via two separate paths. It can also inherit directly as shown by the broken line. The ‘grandparent’ is sometimes referred to as indirect base class.
Grandparent
Parent 1
Parent 2
Child . Multipath inheritance All the public and protected members of ‘grandparent’ are inherited into ‘child’ twice, first via ‘parent1’ and again via ‘parent2. This means, ‘child’ would have duplicate sets of the members inherited from ‘grandparent’. This introduces ambiguity and should be avoided. The duplication of inherited members due to these multiple paths can be avoided by making the common base class (ancestor class) as virtual base class while declaring the direct or intermediate base classes as shown below: Class A
//grandparent
{ .... .... }; class B1 : virtual public A // parent1 { .... .... }; class B2 : virtual public A // parent2 { .... .... }; class C : public B1, public B2 // child { . . . . // only one copy of A . . . . //will be inherited };
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
65
When a class is made a virtual base class, C++ takes necessary care to see that only one copy of the class is inherited, regardless of how many inheritance paths exist between the virtual base class and a derived class. Note that the keywords virtual and public may be used in either order. Student
test
sports
Virtual base class Example #include <iostream.h> class student { protected: int roll_number; public: void get_number (int a) { roll_number = a; }
result
void put_number(void) { cout << “Roll No: “ << roll_number << “\n”;} }; class test : virtual public student { protected: float part1, part2; public: void get_marks(float x, float y) { part1 = x; part2 = y; } void put_marks(void) { cout << “Marks obtained: “ << “\n” << “Part1 = “ << part1 << “\n” << “Part2 = “ << part2 << “\n” } }; class sports : public virtual student { protected: float score; public: void get_score(float s) { score = s;} void put_score(void) { cout << “Sports wt: “ << score << “\n\n”; } };
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
66
void result :: display (void) { total = part1 + part2 + score; put_number(); put_marks(); put_score(); cout << “Total score : “ < total << “\n”; } main() { result student_1; student_1.get_number(678); student_1.get_marks(30.5, 25.5); student_1.display( ); } ABSTRACT CLASSES An abstract class is one that is not used to create objects. An abstract class is designed only to act as a base class (to be inherited by other classes). It is a design concept in program development and provides a base upon which other classes may be built. In the previous example, the student class is an abstract class since it was not used to create any objects. CONSTRUCTORS IN DERIVED CLASSES As we know, the constructors play an important role in initializing objects. We did not use them earlier in the derived classes for the sake of simplicity. One important thing to note here is that, as long as no base class constructor takes any arguments, the derived class need to have a constructor function. However, if any base class contains a constructor with one or more arguments, then it is mandatory for the derived class to have a constructor and pass arguments to the base class constructor. Remember, while applying inheritance we usually create objects using the derived class. Thus, it makes sense for the derived class to pass arguments to the base class constructor. When both the derived and base classes contain constructors, the base constructor is executed first and then the constructor in the derived class is executed. In case of multiple inheritance, the base classes are constructed in the order in which they appear in the declaration of the derived class. Similarly, in a multilevel inheritance, the constructors will be executed in the order of inheritance. Since the derived class takes the responsibility of supplying initial values to its base classes, we supply the initial values that are required by all the classes together when a derived class object is declared. How are they passed to the base class constructors so that they can do their job? C++ supports a special argument passing mechanism for such situations. The constructor of the derived class receives the entire list of values as its arguments and passes them on to the base constructors in the order in which they are declared in the derived class. The base constructors are called and executed before executing the statements in the body of the derived constructor.
-The general form of defining a derived constructor is:
derived-constructor
(Arglist 1,
Arglist2,
... ArglishN,
ArglistD
base1 (arglist1), base2 (arglist2), .... .... .... arguments for base(n) baseN (arglistN) { Body of derived constructor } FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
67
The header line of derived-constructor function contains two parts separated by a colon(:). The first part provides the declaration of the arguments that are passed to the derived-constructor and the second part lists the function class to the base constructors. base1(arglist1), base2(arglist2) ... are function calls to base constructors base1( ), bas2( ), . . . . and therefore. Arglist1 through ArglistN are the argument declarations for the base constructions base 1 through baseN. ArglistD provides the parameters that are necessary to initialize the members of the derived class. Example: D(int a1, int a2, float b1, float b2, int d1): A(a1, a2), /*call to constructor A*/ B(b1, b2), /*call to constructor B*/ { d = d1; //executes its own body } A (a1, a2) invokes the base constructor A( ) and B(b1, b2) invokes another base constructor B( ). The constructor D( ) supplies the values for these four arguments. In addition, it has one argument of its own. The constructor D( ) has a total of five arguments. D( ) may be invoked as follows: .... D objD(5, 12, 2.5, 7.54, 30); These values are assigned to various parameters by the constructor D( ) as follwos: 5 12 2.5 7.54 30
a1 a2 b1 b2 d1
The constructors for virtual base classes are invoked before any non-virtual base classes. If there are multiple virtual base classes, they are invoked in the order in which they are declared. Any non-virtual bases are then constructed before the derived class constructor is executed. See Table 8.2 Example #include <iostream.h> class alpha { int x; public: alpha(int i) { x = i; cout << “alpha initialized \n”; } void show_x(void) { cout << “x = “ << x << “\n”; } }; class beta { cloat y; public: beta(float j) { y = j; cout << “beta initialized \n”; } void show_y (void) { cout << “y = : << y << “\n”; } } class gamma: public beta, public alpha {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
68
int m, n; public: gamma (int a, float b, int c, int d): alpha (a), beta(b) { m = c; n = d; cout << “gamma initialized \n”; } void show_mn(void) { cout << “m = “ << m << “\n” << “n = “ << n << “\n”; } }; main() { gamma g(5, 10.75, 20, 30); cout << “\n”; g.show_x(); g.show_y(); g.show_mn(); } Note that beta is initialized first, although it appears second in the derived constructor. This is because it has been declared first in the derived class header line. Also, note that slpha(a) and beta(b) are function calls. Therefore, the parameters should not include types. C++ supports another method of initializing the class objects. This method uses what is known as initialization list in the constructor function. This takes the following form:
constructor (arglist) : initialization-section { assignment-section } The assignment-section is nothing but the body of the constructor function and is used to assign initial values to its data members. The part immediately following the colon is known as the initialization section. We can use this section to provide initial values to the base constructors and also to initialize its own class members. This means that we can use either of the sections to initialize the data members of the constructors class. The initialization section basically contains a list of initializations separated by commas. This list is known as initialization list. Consider a simple example: class XYZ { int a; int b; public: XYZ(int I, int j) : a(I), b(2 *j) { } }; main ( ) { XYZ x(2, 3); } This program will initialize a to 2 and b to 6. Note how the data members are initialized, just by using the variable name followed by the initialization value enclosed in the parenthesis (like a function call). Any of the parameters of the argument list may be used as the initialization value and the items in the list may be in any order. For example, the constructor XYZ may also be written as: XYZ (inti, intj) : b(i), a(i + j) { }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
69
In this case, a will be initialized to 5 and b to 2. Remember, the data members are initialized in the order of declaration, independent of the order in the initialization list. The enables us to have statements such as XYZ (inti, intj) : a(i), b(a + j) { } Here a is initialized to 2 and b to 6. Remember, a which has been declared first is initialized first and then its value is used to initialize b. However, the following will not work: XYZ (int i, int j) : b(i), a(b * j) { } because the value of b is not available to a which is to be initialized first. The following statements are also valid: XYZ (int i, int j) : a(i), {b = j; } XYZ (int i, int j) : (a = i; b = j; } We can omit either section, if it is not needed. Program 8.8 illustrates the use of initialization lists in the base and derived constructors.
Example #include <iostream.h> class alpha { int x; public: alpha(int i) { x = i; cout << “\n alpha constructed”; } void show_alpha (void) { cout << “ x = “ << x << “\n”; } }; class beta { float p, q; public: beta(float a, float b); p (a), q(b+p) { cout << “\n beta constructed”; } void show_beta(void) { cout << “ p = “ << p << “\n”; cout << “ q = “ << q << “\n”; }; }; class gamma : public beta, public alpha { int u, v; public: gamma (int a, int b, float c); alpha (a*2), beta (c, c), u(a) { v = b; cout << “\n gamma constructed”; } void show_gamma (void) { cout << “ u “ << u << “\n”; cout << “ v “ << v << “\n”; } };
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
70
main ( ) { gamma g(2, 4, 2.5); cout << “\n\ Display member values “ << “\n\n”; g.show_alpha(); g.show_beta(); g.show_gamma(); }; Note that the argument list of the derived constructor gamma contains only three parameters a, b and c which are used to initialize the five data members contained in all the three classes. MEMBER CLASSES : NESTING OF CLASSES Inheritance is the mechanism of deriving certain properties of one class into another. We have seen in detail this is implemented using the concept of derived classes. C++ supports yet another way of inheriting properties of one class into another. This approach takes a view that an object can be collection of many other objects. That is, a class can contain objects of other classes as its members as shown below: class alpha { . . . . }; class beta { . . . . }; class gamma { alpha a; // a is an object of alpha class beta b; //b is an object of beta class .... }; All objects of gamma class will contain the objects a and b. This kind of relationship is called containership or nesting. Creation of an object that contains another object is very different than the creation of an independent object. An independent object is created by its constructor when it is declared with arguments. On the other hand, a nested object is created in two stage. First, the member objects are created using their respective constructors and then the other ‘ordinary’ members are created. This means, constructors of all the member objects should be called before its own constructor body is executed. This is accomplished using an initialization list in the constructor of the nested class. Example: class gamma { .... alpha a; //a is object of alpha beta b; //b is object of beta public: gamma (arglist) : a(arglist1), b(arglist2) { //constructor body } }; arglist is the list of arguments that is to be supplied when a gamma object is defined. These parameters are used for initializing the members of gamma. arglist1 is the argument list for the constructor of a and arglist2 is the argument list for the constructor of b. arglist1 and arglist2 may or may not use the arguments from arglist. Remember, a (arglist1) and b (arglist2) are function calls and therefore the arguments do not contain the data types. They are simply variables or constants. Example: gamma (int x, int y, float z) : a(x), b(x, z) { Assignment section(for ordinary other members) }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
71
We can use as many member objects as are required in a class. For each member object we add a constructor call in the initializer list. The constructors of the member objects are called in the order in which they are declared in the nested class. POINTERS, VIRTUAL FUNCTIONS AND POLYMORPHISM Polymorphism is one of the crucial features of OOP. It simply means ‘one name, multiple forms’. We have already seen how the concept of polymorphism is implemented using the overloaded functions and operators. The overloaded member functions are ‘selected’ for invoking by matching arguments, both type and number. This formation is known to the compiler at the compile time and, therefore, compiler is able to select the appropriate function for a particular call at the compile time itself. This is called early binding or static binding or static linking. Also known as compile time polymorphism, early binding simply means that an objects is bound to its function call at compile time. Now let us consider a situation where the function name and prototype is the same in both the base and derived classes. For example, consider the following class definitions: class A { int x; public: void show() {....} //show() in base class }; class B: public A { int y; public: void show() {....} //show () in derived class }; How do we use the member function show( ) to print the values of objects of both the classes A and B? Since the prototype of show( ) is the same in both the places, the function is not overloaded and therefore static binding does not apply. In fact, the compiler does not know what to do and defers the decision. It would be nice if the appropriate member function could be selected while the program is running. This is known as runtime polymorphism. How could it happen? C++ supports a mechanism known as virtual function to achieve runtime polymorphism. Please refer Fig. 9.1. At run time, when it is known what class objects are under consideration, the appropriate version of the function is called. Since the function is linked with a particular class much later after the compilation, this process is termed as late binding. It is also known as dynamic binding because the selection of the appropriate function is done dynamically at runtime. Polymorphism
Compile time Polymorphism
Runtime Polymorphism
Function Operator Virtual overloading overloading functions FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
72
Dynamic binding is one of the powerful features of C++,. This requires the use of pointers to objects. We shall discuss in detail how the object pointers and virtual functions are used to implement dynamic binding. POINTERS TO OBJECTS We have already seen how to use pointers to access the class members. As stated earlier, a pointer can point to an object created by a class. Consider the following statement: item x; where item is a class and x is an object defined to be of type item. Similarly we can define a pointer it_ptr of type item as follows: item * it_ptr; Object pointers are useful in creating objects at run time. We can also use an object pointer to access the public members of an object. Consider a class item defined as follows: class item { int code; float price; public: void getdata(int a, float b) { code = a; price = b; } void show(void) { cout << “Code :” << code << “\n”; cout << “Price :” << price << “\n”; } }; Let us declare an item variable x and pointer ptr to x as follows: item x; item *ptr = &x; The pointer ptr is initialized with the address of x. We can refer to the member functions of item in two ways, one by using the dot operator and the object, and another by using the arrow operator and the object pointer. The statements x.getdata(100,75.50); x.show(); are equivalent to ptr =>getdata(100, 75.50); ptr=>show() Since *ptr is an alias of x, we can also use the following method: (*ptr).show(); The parentheses are necessary because the dot operator has higher precedence than the indirection operator *. We can also create the objects using pointers and new operator as follows: item *ptr = new item; This statement allocates enough memory for the data members in the object structure and assigns the address of the memory space to ptr. The ptr can be used to refer to the members as shown below:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
73
ptr ->show( ); If a class has a constructor with arguments and does not include an empty constructor, then we must supply the arguments when the object is created. We can also create an array of objects using pointers. For example, the statement item *ptr = new item[10]; //array of 10 objects creates memory space for an array of 10 object of item. Remember, in such cases, if the class contains constructor, it must also contain an empty constructor. #include <iostream.h> class item { int code: float price; public: void getdata(int a, float b) { code = a; price = b; } void show(void) { cout << “Code : “ << code << “\n”; cout << “Price: “ << price << “\n”; } }; const int size = 2; main() { item *P = new item [size]; item *d = p; int x, i; float y; for(i = 0; i < size; i++) { cout << “Input code and price for item” << i+1; cin >> x >> y; p++; } for (i = 0; i< size; i++) { cout << “Item:” << i+1 << “\n”; d->show(); d++; } } For example, the objects of a class that contain character strings would not be of the same size. In such cases, we can define an array of pointers to objects that can be used to access the individual objects. #include <iostream.h> #include <string.h> class city { protected: char *name; int len; public: city()
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
74
{ len = 0; name = new char (len+1); } void getname(void) { char *s; cout << “Enter city name:”; cin >> s; len = strlen(s); name = new char[len + 1]; strcpy(name, s); } void printname(void) { cout << name << “\n”; } }; main() { city *cptr[10]; //ARRAY OF 10 POINTERS to cities int n = 1; int option; do { cptr [n] = new city; //create new city cptr[n]-> getname(); n++; cout << “Do you want to enter one more name?\n”; cout << “(Enter 1 for yes 0 for no):”; cin >> option; while(option); cout << “\n\n”; for(int i = 1; i < = n; i++) cptr[i]->printname(); } this POINTER C++ uses a unique keyword called this to represent an object that invokes a member function. this is a pointer that points to the object for which this function was called. For example, the function call A.max( ) will set the pointer this to the address of the object A. The starting address is the same as the address of the first variable in the class structure. This unique pointer is automatically passed to a member function when it is called. The pointer this acts as an implicit argument to all the member functions. Consider the following simple example: class ABC { int a; .... .... }; The private variable a can be used directly inside a member function, like a = 123; We can also use the following statement to do the same job; this ->a = 123;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
75
Since C++ permits the use of shorthand form a = 123, we have not been using the pointer this explicitly so far. However, we have been implicitly using the pointer this when overloading the operators using member function. Recall that, when a binary operator is overloaded using a member function, we pass only one argument to the function. The other argument is implicitly passed using the pointer this. One important application of the pointer this is to return the object it points to. For example, the statement return *this; inside a member function will return the object the invoked the function. This statement assumes importance when we want to compare two or more objects inside a member function and return the invoking object as a result. Example: person & person :: greater(person & x) { if x.age > age return x; //argument object else return *this; //invoking object } Suppose we invoke this function by the call max = A.greater(B); The function will return the object B (argument object) if the age of the person B is greater than that of A, otherwise, it will return the object A (invoking object) using the pointer this. Remember, the deference operator * produces the contents at the address contained in the pointer #include <iostream.h> #include <string.h> class person { char name[20]; float age; public: person(char *s, float a) { strcpy(name, s); age = a; } person & person :: greater (person & x) { if (x.age >= age) return x; else return *this; } void display(void) { cout < “Name: “ << name << “\n” << “Age:” << age << “\n”; } }; main() { person P1(“John”, 37.50),
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING P2(“Ahmed”, 29.0), P3(“Hebber”, 40.25), person P(‘\0’, 0); P = P1.greater(Pe); cout << “Elder person is: \n”; P.display(); P = p1.greater (P2); cout << “Elder person is: \n”; P.display();
76
//P3.greater(P1)
} POINTERS TO DERIVED CLASSES We can use pointers not only to the base objects but also to the objects of derived classes. Pointers to objects of a base class are type-compatible with pointers to objects of a derived class. Therefore, a single pointer variable can be made to point to objects belonging to different classes. For example, if B is a base class and D is a derived class from B, then a pointer declared as a pointer to B can also be a pointer to D. Consider the following declarations: B * cptr; B b; D d; cptr = & b;
//pointer to class B type variable //base object //derived object //cptr points to object b
We can make cptr to point to the object d as follows: cptr = &d; //cptr points to object d This is perfectly valid with C++ because d is an object derived from the class B. However, there is a problem in using cptr to access the public members of the derived class D. Using cptr. We can access only those members inherited from B and not the members that originally belong to D. In case a member of D has the same name as one of the members of B, then any reference to that member by cptr will always access the base class member. Although C++ permits a base pointer to point to any object derived from the base, the pointer cannot be directly used to access all the members of the derived class. We may have to use another pointer declared as pointer to the derived type. #include <iostream.h> class BC { public: int b; void show() { cout << “b = “ << b << “\n”; } }; class DC : public BC { public: int d; void show() { cout << “b = “ << b << “\n”; << “d = “ << d << “\n”; } }; main() { BC * bptr; BC base; bptr = &base;
//base pointer //base address
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
77
bptr-> b = 100; //access BC via base pointer cout << “bptr points to base object \n”; bptr -> show (); //derived class DC derived; bptr = &derived; //address of derived object hptr -> b = 200; //access DC via base pointer /* bptr -> d = 300; *//won’t work cout << “bptr now points to derived object \n”; bptr -> show(),; //bptr now points to derived object /* accessing d using a pointer of type class DC */ DC *dptr; dptr = &derived; dptr->d = 300;
//derived type pointer
cout << “dptr is derived type pointer\n”; dptr -> show(); cout << “using ((DC *) bptr)\n”; ((DC *)bptr) -> d = 400; ((DC *)bptr) -> show(); } Note that we have used the statement bptr->show( ); two times. First, when bptr points to the base object and second, when bptr is made to point the derived object. But, both the times, it executed BC::show( ) function and displayed the content of the base object. However, the statements dptr -> show ( ); ((DC*) bptr) -> show(); //cast pbtr to DC type display the contents of the derived object. This shows that, although a base pointer can be made to point to any number of derived objects, it cannot directly access the members defined by a derived class. VIRTUAL FUNCTIONS As mentioned earlier, polymorphism refers to the property by which objects belonging to different classes are able to respond to the same message, but in different forms. An essential requirement of polymorphism is therefore the ability to refer to objects without any regard to their classes. This necessitates the use of a single pointer variable to refer to the objects of different classes. Here, we use the pointer to base class to refer to all the derived objects. But, we just discovered that a base pointer, even when it is made to contain the address of a derived class, always executes the function in the base class. The compiler simply ignores the contents of the pointer and chooses the member function that matches the type of the pointer. How do we then achieve polymorphism? It is achieved using what is known as ‘virtual’ functions. When we use the same function name in both the base and derived classes, the function in base class is declared as virtual using the keyword virtual preceding its normal declaration. When a function is made virtual , C++ determines which function to use at run time based on the type of object pointed to by the base pointer, rather than the type of the pointer. Thus, by making the base pointer to point to different objects, we can execute different versions of the virtual function. #include <iostream.h> class Base { public:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
78
void display() { cout << “\n Display base “; } virtual void show() {cout << “\n show base”; } }; class Derived : public Base { public: void display() {cout << “\n Display derived”; } void show() {cout << “\n show derived”; } }; main () { Base B; Derived D; Base *bptr; //Declarations cout << “\n bptr points to Base \n”; bptr = &B; bptr -> display(); //calls Base version bptr -> show(); //calls Base version cout << “\n\n bptr points to Derived\n”; bptr = &D; bptr -> display(); //calls Base version bptr -> show(); //calls Derived version } Note that when bptr is made to point to the object D, the statement bptr -> display(); calls only the function associated with the Base (i.e. Base :: display( )) whereas the statement bptr -> show(); calls the Derived version of show( ). This is because the function display( ) has not been made virtual in the Base class. One important point to remember is that, we must access virtual functions through the use of a pointer declared as a pointer to the base class. Why can’t we use the object name (with the dot operator) the same way as any other member function to call the virtual functions? We can, but remember, runtime polymorphism is achieved only when a virtual function is accessed through a pointer to the base class. Let us take an example where virtual functions are implemented in practice. Consider a book shop which sells both books and video-tapes. We can create a class known as media that stores the title and price of a publication. We can then create two derived classes, one for storing the number of pages in a book and another for storing the playing time of a tape. Figure 9.2 shows the class hierarchy for the book shop.
A function display( ) is used in all the classes to display the class contents. Notice that the function display( ) has been declared virtual in media, the base class. In the main program we create a heterogeneous list of pointers of type media as shown below: media *list[2] = {&book1, &tape1}; The base pointers list[0] and list[1] are initialized with the addresses of objects book 1 and tape1 respectively. #include <iostream.h> #include <string.h> class media { protected: char title[50];
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING float price; public: media(char *s, float a) { strcpy(title, s); price = a; } virtual void display(){ }//empty virtual function }; class book: public media { int pages; public: book(char *s, float a, int p): media(s,a) { pages = p; } void display( ); }; class tape : public media { float time; public: tape(char *s, float a, float t):media (s,a) { time = t; } void display(); }; void book :: display() { cout << “\n Title: “ << title; cout << “\n Pages: “ << pages; cout << “\n Price: “ << price; } void tape :: display() { cout << “\n Title: “ << title; cout << “\n play time: “ << time << “mins”; cout << “\n Price: “ << price; } main() { char * title; float price, time; int pages; cout << “\n ENTER BOOK DETAILS\n”; cout << “ Title: “; cin >> title; cout << “ Price: “; cin >> price; cout << “ Pages: “; cin >> pages; book book1 (title, price, pages); cout << “\n ENTER TAPE DETAILS\n”; cout << “ Title: “; cin >> title; cout << “ Price: “; cin >> price; cout << “ play time (mins): “; cin >> time; tape tape1 (title, price, time); media* list[2]; list[0] = &book1; list[1] = &tape1; cout << “\n MEDIA DETAILS”;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
79
OBJECT ORIENTED PROGRAMMING
80
cout << “\n ...... BOOK ......”; list[0] -> display(); //display book details cout << “\n ......TAPE ......”; list[1] -> display(); //display tape details } Rules for Virtual Functions When virtual functions are created for implementing late binding, we should observe some basic rules that satisfy the compiler requirements: 1. The virtual functions must be members of some class. 2. They cannot be static members. 3. They are accessed by using object pointers. 4. A virtual function can be a friend of another class. 5. A virtual function in base class must be defined, even though it may not be used. 6. The prototypes of the base class version of a virtual function and all the derived class versions must be identical. If two functions with the same name have different prototype, C++ considers them as overloaded functions, and the virtual function mechanism is ignored. 7. We cannot have virtual constructors, but we can have virtual destructors. 8. While a base pointer can point to any type of the derived object, the reverse is not true. That is, we cannot use a pointer to a derived class to access an object of the base type. 9. When a base pointer points to a derived class, incrementing or decrementing it will not make it to point to the next object of the derived class. It is incremented or decremented only relative to its base type. Therefore, we should not use this method to move the pointer to the next object. 10. If a virtual function is defined in the base class, it need not be necessarily redefined in the derived class. In such cases, calls will invoke the base function. PURE VIRTUAL FUNCTIONS It is normal practice to declare a function virtual inside the base class and redefine it in the derived classes. The function inside the base class is seldom used for performing any task. It only serves as a placeholder. For example, we have not defined any object of class media and therefore the function display( ) in the base class has been defined ‘empty’. Such functions are called “donothing” functions. A “do-nothing’ function may be defined as follows: virtual void display( ) = 0; Such functions are called pure virtual functions. A pure virtual function is a function declared in a base class that has no definition relative to the base class. In such cases, the compiler requires each derived class to either define the function or redeclare it as a pure virtual function. Remember that a class containing pure virtual functions cannot be used to declare any objects of its own. As stated earlier, such classes are called abstract base classes. The main objective of an abstract base class is to provide some traits to the derived classes and to create a base pointer required for achieving runtime polymorphism.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
81
UNIT III MANAGING CONSOLE I/O OPERATIONS Every program takes some data as input and generates the processed data as output following the familiar input-output cycle. It is, therefore, essential to known how to provide the input data and how to present the results in a desired form. We have, in the earlier chapters, used cin and cout with the operators >> and << for the input and output operations. But we have not so far discussed as to how to control the way the output is printed. C++ supports a rich set of I/O functions and operations to do this. Since these functions use the advanced features of C++ (such as classes, derived classes and virtual functions) we need to know a lot about them before really implementing the C++ I/O operations. Remember, C++ supports all of Câ&#x20AC;&#x2122;s rich set of I/O functions. We can use any of them in the C++ programs. But we restrained from using the due to two reasons. First, I/O methods in C++ support the concepts of OOP and secondly, I/O methods in C cannot handle the user-defined data types such as class objects. C++ uses the concept of stream and stream classes to implement its I/O operations with the console and disk files. We will discuss in this chapter, how stream classes support the console oriented input-output operations. File-oriented I/O operations will be discussed in the next chapter. C++ STREAMS The I/O system in C++ is designed to work with a wide variety of devices including terminals, disks, and tape drives. Although each device is very different, the I/O system supplies and interface to the programmer that is independent of the actual device being accessed. This interface is known as stream. A stream is a sequence of bytes. It acts either as a source from which the input data can be obtained or as a destination to which the output data can be sent. The source stream that provides data to the program is called the input stream and the destination stream and receives output from the program is called the output stream. In other words, a program extracts the bytes from an input stream and inserts bytes into an output stream as illustrated in Fig. 10.1 . The data in the input stream can come from the keyboard or any other storage device. Similarly, the data in the output stream can go to the screen or any other storage device. As mentioned earlier, a stream acts as an interface between the program and the input/output device. Therefore, a C++ program handles data (input or output) independent of the devices used.
Input Stream Input device
extraction from input stream Program
Output Stream Output device
insertion into output stream
C++ contains several pre-defined streams that are automatically opened when a program begins its execution. These include cin and cout which have been used very often in our earlier programs. We know that cin represents the input stream connected to the standard input device (usually the keyboard) and cout represents the output stream connected to the standard output
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
82
device (usually the screen). Note that the keyboard and the screen are default options. We can redirect streams to other devices or files, if necessary. C++ STREAM CLASSES The C++ I/O system contains a hierarchy of classes that are used to define various streams to deal with both the console and disk files. These classes are called stream classes. Figure 10.2 shows the hierarchy of the stream classes used for input and output operations with the console unit. These classes are declared in the header file iostream.h. This file should be included in all the programs that communicate with the console unit. ios
pointer istream
streambuf
ostream
input output
iostream
istream_withassign
iostream_withassign
ostream_withassign
As seen in Figure, ios is the base class for istream (input stream) and ostream (output stream) which are, in turn, base classes for iostream (input/output stream). The class ios is declared as the virtual base class so that only one copy of its members are inherited by the iostream. The class ios provides the basic support for formatted and unformatted I/O operations. The class istream provided the facilities for formatted and unformatted input while the class ostream (through inheritance) provides the facilities for formatted output. The class iostream provides the facilities for handling both input and output streams. There classes, namely, istream_withassign, ostream_withassign, and ostream_withassign and assignment operators to these classes. Table 10.1 gives the details of these classes. Class name
contents
Ios (General input/output stream class)
Contains basic facilities that are used by all other input and output classes. It also contains a pointer to a buffer object (streambuf object). Declares constants and functions that are necessary for handling formatted input and output operations.
istream (Input stream)
Inherits the properties of ios. Declares input functions such as get( ). Contains overloaded extraction operator>>
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
83
ostream (Output stream)
Inherits the properties of ios. Declares input functions such as put( ) and write( ). Contains overloaded extraction operator <<
iostream (input/output stream)
Inherits the properties of ios istream and ostream through multiple inheritance and thus contains all the input and output functions.
Streambuf
Provides in interface to physical devices through buffers. It acts as a base for filebuf class used in files.
UNFORMATTED I/O OPERATIONS Overloaded Operators >> and << We have used the objects cin and cout (pre-defined in the iostream.h file) for the input and output of data of various types. This has been made possible by overloading the operators >> and << to recognize all the basic C++ types. The >> operator is overloaded in the istream class and << is overloaded in the istream class. The following is the general format for reading data from the keyboard;
Cin >> variable1 >> variable2 >> ....>>variableN; Variable1, variable2, ...... are valid C++ variable names that have been declared already. This statement will cause the computer to stop the execution and look for input data from the keyboard. The input data for this statement would be: data1
data ..... data N
The input data are separated by white spaces and should match the type of variable in the cin lit. Spaces, newlines and tabs will be skipped. int code; cin >> code; Suppose the following data is given as input: 4258D The operator will read the characters upto 8 and the value 4258 is assigned to code. The character D remains in the input stream and will be input to the next cin statement. The general from for displaying data on the screen is:
cout << item1 << item2 << ... << itemN;; The items item1 through itemN may be variables for constants of any basic type. We have used such statements in a number of examples illustrated in previous chapters.
put( ) and get( ) Functions The classes istream and oustream define two member functions get( ) and put( ) respectively to handle the single character input/output operations. There are two types of get( )
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
84
functions. We can use both get(char *) and get(void) prototypes to fetch a character including the blank space, tab and the newline character. The get(char *) version assigns the input character to its argument and the get(void) version returns the input character. Since these functions are members of the input/output stream classes, we must invoke them using an appropriate object. Example: char c; cin.get(c); while(c != ‘\n’) { cout << c; cin.get(c); }
//get a character from keyboard //and assign it to c
//display the character on screen //get another character
This code reads and displays a line of text (terminated by a newline character). Remember, the operator >> can also be used to read a character but it will skip the while spaces and newline character. The above while loop will not work properly if the statement cin >> c; is used in place of cin.get(c); Try using both of them and compare the results. The get(void) versions is used as follows: .... char c; c = cin.get(); //cin.get(c); replaced .... ....
The value returned by the function get( ) is assigned to the variable c. The function put( ), a member of ostream class, can be used to output a line of text, character by character. For example, cout.pt(‘x’); displays the character x and cout.put(ch); displays the value of varibale ch. The variable ch must contain a character value. We can also use a number as an argument to the function put( ). For example cout.put(68). displays the character D. This statement will convert the int value 68 to a char value and display the character whose ASCII value is 68. The following segment of a program reads a line of text from the keyboard and displays it on the screen.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING char c; cin.get(c); while(C != ‘\n’) { cout.put(c); cin.get(c); }
85
//read a character
//display the character on screen
#include <iostream.h> main() { int cout = 0; char c; cout << “INPUT TEXT\n”; cin.get(c); while(c != ‘\n’) { cout.put(c); cout++; cin.get(c); } cout << “\nNumber of characters = “ <<count << “\n”; } When we type a line of input, the text is sent to the program as soon as we press the RETURN key. The program then roads one character at a time using the statement cin.get(c); and displays it using the statement cout.put(c); The process is terminated when the newline character is encountered. getline( ) and write( ) functions We can read and display a line of text more efficiently using the line-oriented input/output functions getline( ) and write( ). The getline( ) functions reads a whole line of text that ends with a newline character (transmitted by the RETURN key). This function can be invoked by using the object cin as follows.
cin. getline (line, size); This function call invokes the fnction getline( ) which reads character input into the variable line. The reading is terminated as soon as either the newline character ‘\n’ is encountered or size-1 characters are read (whichever occurs first). The newline character is read but not saved. Instead, it is replaced by the null character. For example, consider the following code: char name[20]; cin.getline(name, 20); Assume that we have given the following input through the keyboard: Bjarne Stroustrup <press RETURN> This input will be read correctly and assigned to the character array name. Let us suppose the input is as follows: Object Oriented Programming <press RETURN> In this case, the input will be terminated after reading the following 19 characters: object Oriented Pro Remember, the two blank spaces contained in the string are also taken into account. We can also read strings using the operator >> as follows:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
86
cin >> name; But remember cin can read strings that do not contain white spaces. This means that cin can read just one word and not a series of words such as “Bjarne Stroustrup”. But it can read the following string correctly: Bjarne_Stroustrup After reading the string. cin automatically adds the terminating null character to the character array. #include <iostream.h> main( ) { int size = 20; char city[20]; cout << “Enter city name: \n”; cin >> city; cout << “City name:” << city << “\n\n”; cout << “Enter city name again: \n”; cin.getline(city, size); cout << “City name now:” << city << “\n\n”; cout << “Enter another city name: \n”; cin.getline(city, size); cout << “New City name:” << city << “\n\n”; } The write( ) function displays an entire line and has the following form:
cout.write(line, size); The first argument line represents the name of the string to be displayed and the second argument size indicates the number of characters to display. Note that it does not stop displaying the characters automatically when the null character is encountered. If the size is greater than the length of line, then it displays beyond the bound of line. Program 10.3 illustrates how write( ) method displays a string. #include < iostream.h> #include <string.h> main() { char * string1 = “C++ “; char * string2 = “Programming”; int m = strlen(string1); int n = strlen(string2); for (int i = 1; i < n; i++) { cout.write(string2, i): cout << “\n”; } for(i = n; i > o; i--) { cout.write(string2, i); cout << “\n”; } //................... concatenating strings cout.write(string1, m).write(string2, n); cout << “\n”: //................ crossing the boundry cout.write(string1, 10); } It is possible to concatenate two strings using the write( ) function. The statement
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
87
cout.write(string1,m).write(wrting2,n); is equivalent to the following two statements; cout.write(string1, m); cout.write(string2,n);
FORMATTED CONSOLE I/O OPERATIONS C++ supports a number of features that could be used for formatting the output. These features include: ios class functions and flags. Manipulators. User-defined output functions. The ios class contains a large number of member functions that would help us to format the output in a number of ways. ios format functions Function width( )
Task To specify the required field size for displaying an output value
Precision( ) To specify the number of digits to be displayed after the decimal point of a float value. fill( ) To specify a character that is used to fill the unused portion of a field. setf( ) To specify format flags that can control the form of output display (such as left-justification and right-justification). unsetf( )
To clear the flags specified.
Manipulators are special functions that can be included in the I/O statements to alter the format parameters of a stream. Table 10.3 shows some important manipulator functions that are frequently used. To access these manipulators, the file iomanip.h should be included in the program. Manipulators Manipulators
Equivalent ios function
setw( )
width( )
setprecision( )
precision( )
setfill( )
fill( )
setiosflags( )
setf( )
resetiosflags( )
unsetf( )
In addition to these functions supported by the C++ library, we can create our own manipulator functions to provide any special output formats. The following sections will provide details of how to use the pre=defined formatting functions and how to create new ones.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
88
Defining Field Width: width( ) We can use the width( ) function to define the width of a field necessary for the output of an item. Since, it is a member function, we have to use an object to invoke it, as show below:
cout.width (w); Where w is the field with (number of columns). The output will be printed in a field of w characters wide at the right end of the field. The width( ) function can specify the field width for only one item (the item that follows immediately). After printing one item (as per the specifications) it will revert back to the default. For example, the statements cout.width(5); cout << 543 << 12 << “\n”; will produce the following output: 5
4
3
1
2
The value 543 is printed right-justified in the first five columns. The specification width(5) does not retain the setting for printing the number 12. This can be improved as follows. cout.width(5); cout << 543; cout.width(5); cout << 12 << “\n”; This produces the following output: 5
4
3
1
2
Remember that the field width should be specified for each item separately. C++ never truncates the value and therefore, if the specified field width is smaller than the size of the value to be printed, C++ expands the field to fit the value #include <iostream.h> main( ) { int items[4] = {10, 8, 12, 15}; int cost [4] = 175, 100, 60, 99}; cout.width(5); cout << “ITEMS”; cout.width(8); cout << “COST”; cout.width(15); cout << “TOTAL VALUE” << “\n”; int sum = 0; for (int i=0; i < 4; i++) { cout.width(5); cout.width(8);
cout << items[i]”; cout << cost[i];
int value = items[i] * cost[i] cout.width(15); cout << value << “\n”; sum = sum + value; } cout << “\n Grand Total = “; cout.width(2); cout << sum << “\n”; }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
89
Note that a field of width two has been used for printing the value of sum and the result is not truncated. A good gesture of C++! Setting Precision: precision( ) By default, the floating numbers are printed with six digits after the decimal point. However, we can specify the number of digits to be displayed after the decimal point while printing the floatingpoint numbers. The can be done by using the precision( ) member function as follows:
cout.precision (d); Where d is the number of digits to the right of the decimal point. For example, the statements cout.precision(3); cout << sqrt(2) << “\n”; cout << 3.14159 << “\n”; cout << 2.50032 << “\n”; will produce the following output: 1.141 3.142 2.5
(truncated) (rounded to the nearest cent) (no trailing zeros)
Note that, unlike the function width( ), precision( ) retains the setting in effect until it is reset. That is why we have declared only one statement for the precision setting which is used by all the three outputs. We can set different values to different precisions as follows: cout.precision(3); cout << sqft(2) << “\n”; cout.precision(5); cout << 3.14159 << “\n”; We can also combine the field specification with the precision setting. Example: cout.precision(2); cout.width(5); cout << 1.2345; The first two statements instruct: “print two digits after the decimal point in a field of five character width”. Thus, the output will be: 1
2
3
#include <iostream.h> #include <math.h> main() { cout << “precision set to 3 digits \n\n”; cout.precision(3); cout.width(10); cout << “VALUE”; cout.width (15); cout << “SQRT_OF_VALUE” << “\n”; for (int n = 1; n <= 5; n++) { cout.width(8)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
90
cout << n; cout.width(13); cout << sqrt(n) << “\n”; } cout << “\n Precision set to 5 digits \n\n”; cout.precision(5); //precision parameter changed cout << “sqrt(10) = “ << sqrt(10) << “\n\n”; cout.precision(0); //precision set to default cout << “sqrt(10) = “sqrt(10)<< “(default setting)\n”; } Filling and Padding: fill( ) We have been printing the values using much larger field widths than required by the values. The unused positions of the field are filed with white spaces, by default. However, we can use the fill( ) function to fill the unused positions by any desired character. It is used in the following form:
cout.fill (ch); Where ch represents the character which is used for filling the unused positions. Example: cout.fill(‘*’); cout.width(10); cout << 5250 << “\n”; The output would be:
*
*
*
*
*
*
5
2
5
0
Financial institutions and banks use this kind of padding white printing cheques so that no one can change the amount easily. Like precision( ), fill( ) stays in effect till we change it. Se Program 10.6 and its output. #include <iostream.h> main( ) { cout.fill(‘<’); for (int n = 1; n <=6; n++) { cout.width(5); cout << n; cout.width(10); cout << 1.0 / float(n) << “\n”; if (n == 3) cout.fill(‘>’); } cout << “\nPadding changed \n\n”; cout.fill(‘#’); //fill() reset cout.width915); cout << 12.345678 << “\n”; } Formatting Flags, Bit-fields and setf( ) We have seen that when the function width( ) is used, the value (whether text or number) is printed right-justified in the field width created. But, it is a usual practice to print the text left-justified. How do we get a value printed left-justified? Or, how do we get a floating-point number printed in the scientific notation? The self( ), a member function of the ios class, can provide answers to these and many other formatting questions. The setf( ) (self stands for set flags) function can be used as follows:
cout.setf (arg1, arg2);
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
91
The arg1 is one of the formatting flags defined in the class ios. The formatting flag specifies the format action required for the output. Another ios constant, arg2, knwon as bit field specifies the group to which the formatting flag belongs. Table shows the bit fields, flags and their format actions. There are three bit fields and each has a group of format flags which are mutually exclusive. Examples: cout.setf(ios::left, ios::adjustifield); cout.setf(ios::scientific, ios::floatifield); Note that the first argument should be one of the group members of the second argument. Flags and bit fields for setf( ) function Format required
Flag (art1)
Bit-field (arg2)
Left-justified output
ios :: left
ios :: adjustifield
Right-justified output
ios :: right
ios :: adjustifield
Padding after sign or base indicator (like+##20)
ios :: internal
ios :: adjustified
Scientific notation
ios::scientific
ios :: floatifield
Fixed point notation
ios::fixed
ios :: floatfield
Decimal base
ios :: dec
ios :: basefield
Octal base
ios :: oct
ios :: basefield
Hexadecimal base
ios :: hex
ios :: basefield
Consider the following segment of code: cout.fill(‘*’); cout.setf(ios::left, ios::adjustfield); cout.width(15); cout << “TABLE 1” << “\n”; This will produce the following output; T
A
B
L
E
1
*
*
*
*
*
*
*
*
This statements cout.fill(‘*’); cout.precision(3); cout.setf(ios::internal, ios::adjustifild); cout.setf(ios::scientific, ios::floatfield); cout.width(15); cout <<-12.34567 << “\n”; will produce the following output: Note that the sign is left-justified and the value is right left-justified. -
*
*
*
*
*
1
.
2
3
5
3
+
0
1
Displaying Trailing Zeros and Plus Sign If we print the numbers 10.75, 25.00 and 15.50 using a field width of, say, eight positions, with two digits precision, then the output will be as follows:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
1
0
.
7
5
2
5
92
1 5 . 5 Note that the trailing zeros in the second and third items have been truncated. Certain situations, such as a list of prices of items of the salary statement of emloyees, require trailing zeros to be show. The above output would look better if they are printed as follows: 10.75 25.00 15.50 The self( ) can be used with the flag ios::showpoint as a single argument to achieve this form of output. For example, cout.setf(ios::showpoint);
//display trailing zeros
would cause cout to display trailing zeros and trailing decimal point. Under default precision, the value 3.25 will be displayed as 3.250000. Remember, the default precision assumes a precisions of six digits. Similarly, a plus sign can be printed before a positive number using the following statement: cout.setf(ios::showpos); //show + sign For example, the statements cout.setf(ios::showpoint); cout.setf(ios::showpos); cout.precision(3); cout.setf(ios::fixed, ios::floatfield); cout.setf(ios::internal, ios::adjustfield); cout.width(10); cout << 275.5 << â&#x20AC;&#x153;\nâ&#x20AC;?; will produce the following output: +
2
7
5
1
.
5
0
0
The flags such as shwpoint and showpos do not have any bit fields and therefore are used as single arguments in setf( ). This s possibl because the setf( ) has been declared as an overloaded function in the class ios. Table lists the flags that do not possess a named bit field. These flags are not mutually exclusive and therefore can be set or cleared independently. Flags that do not have bit fields Flag ios::showbase ios::showpos ios::showpoint ios::uppercase ios::skipus ios::unitbuf ios::stdio #include <iostream.h> #include <math.h>
Meaning Use base indicator on output Print + before positive numbers Show trailing decimal point and zeroes Use uppercase letters for hex output Skip white space on input Flush all streams after insertion Flush stdout and stderr after insertion
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
93
main( ) { cout.fill(‘*’); cout.setf(ios::left, ios::adjustfield); cout.width(10); cout << “VALUE”; cout.setf(ios::right, ios::adjustfield); cout.width(15); cout << “SQRT OF VALUE” << “\n”; cout.fill(‘.’); cout.precision(4); cout.setf(ios::showpoint); cout.setf(ios::showpoint); cout.setf(ios::fixed, ios::floatfield) for (int n = 1; n <= 10; n++) { cout.setf(ios::internal, ios::adjustfield); cout.width(5); cout << n; cout.setf(ios::right, ios::adjustfield); cout << sqrt(n) << “\n”; } //floatfield changed cout.setf(ios::dcientif, ios::floatfield); cout << “\nSQRT(100) = “ << sqrt(100) << “\n”; } 1. 2. 3. 4.
The flags set by setf( ) remain effective until they are reset or unset. A format flag can be reset any number of times in a program. We can apply more than one format controls jointly on an output value. The setf() sets the specified flags and leaves others unchanged.
MANAGING OUTPUT WITH MANIPULATORS The header file iomanip.h provides a set of functions called manipulators which can be used to manipulate the output formats. They provide the same features as that of the ios member functions and flags. Some manipulators are more convenient to use than their counterparts in the class ios. For example, two or more manipulators can be used as a chain in one statement as show below: cout << manip1 << manip2 << manip3 << item; cout << manip1 << item1 << manip2 << item2; This kind of concatenation is useful when we want to display several columns of output. The most commonly used manipulators are shown in Table 10.6. The table also gives their meaning and equivalents. To access these manipulators, we must include the file iomanip.h in the program. Manipulator
Meaning
Equivalent
setw(int w)
Set the field width to w.
width( )
setprecision(int d)
Set the floating point precision to d.
precision( )
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
94
setfill(int c)
Set the fill character to c.
fill( )
setiosflags(long f)
Set the format flag f
setf( )
resetiosflags(long f)
Clear the flag specified by f.
unsetf( )
endi
Insert new line and flush stream
“\n”
Some examples of manipulators are given below: cout << setw(10) << 1.2345 This statement prints the value 12345 right-justified in a field width of 10 characters. The output can be made left-justified by modifying the statement as follows: cout << setf(10) << setiosflags(ios::left) << 12345; One statement can be used to format output for two or more values. For example, the statement cout << setw(5) << setprecision(2) << 1.2345 << setw(10) << setprecision(4) << sqrt(2) << setw(15) << setiosflags(ios::scientific) << sqrt(3) << endl; will print all the three values in one line with the field sizes of 5, 10, and 15 respectively. Note that each output is controlled by different set of format specifications. We can jointly use the manipulators and the ios functions in a program. segment of code is valid:
The following
cout.setf(ios::showpoint); cout.setf(ios::showpos); cout << setprecision(4); cout << setiosflags(ios::scientific); cout << setw(10) << 123.45678; There is a major difference in the way the manipulators are implemented as compared to the ios member functions. The ios member function returns the previous format state which can be used later, if necessary. But the manipulator does not return the previous format state. In case, we need to save the old format states, we must the ios member functions rather than the manipulators. Example: cout.precision(2); //previous state int p = cout.precision(4); //current state When these statements are executed, p will hold the value of 2 (previous state) and the new format state will be 4. We can restore the previous format state as follows: cout.precision(p); //p = 2 Program 10.8 illustrates the formatting of the out value using both manipulators and ios functions. #include <iostream.h> #include <iomanip.h> main() { cout.setf(ios::showpoint); cout << setw(5) << “n” << setw(15)<< “Inverse_of_n”
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
95
<< setw(15)<< “Sum_of_terms\n\n”; double term, sum = 0; for (int n = 1; n <= 10; n++) { term = 1.0 / float (n); sum = sum + term; cout << setw(5) << n << setw(14) << setprecision(4) << setiosflags (ios::scientific)<< term << setw(13)<< resetiosflags(ios::scientific) << sum << end1; } } We can design our own manipulators for certain special purposes. The general form for creating a manipulator without any arguments is:
ostream & manipulator (ostream & output) { .... . . . . (code) .... return output; } Here, the manipulator is the name of the manipulator under creation. The following function defines a manipulator called unit that displays “inches”; ostream & unit (ostream & output) { output << “inches”; return output; } The statement cout << 36 << unit; will produce the following output 36 inches We can also create manipulators that could represent a sequence of operations, Example: ostream & show(ostream & output) { output.setf(ios::showpoint); output.setf(ios::showpos); output << setw(10); return output; } This function defines a manipulator called show that turns of the flags showpoint and showpos declared in the class ios and sets the filed width to 10. #include <iostream.h> #include <iomanip.h> //user-defined manipulators ostream & currency(ostream & output)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
96
{ output << “Rs”; return output; } ostream & form(ostream & output); { output.setf(ios::showpos); output.setf(ios::showpoint); output.fill(‘*’); output.precision(2); output << setiosflags(ios::fixed) << setw(10); return output; } main() { cout << currency << form << 7864.5; } WORKING WITH FILES Many real-life problems handle large volumes of data and, in such situations, we need to use some devices such as floppy disk or hard disk to store the data. The data is stored in these devices using the concept of files. A file is a collection of related data stored in a particular area on the disk. Programs can be designed to perform the read and write operations on these files. A program typically involves either or both of the following kinds of data communication. 1. Data transfer between the console unit and the program. 2. Data transfer between the program and a disk file. We have already discussed the technique of handling data communication between the console unit and the program. In this chapter, we will discuss various methods available for storing and retrieving the data from files. The I/O system of C++ handles file operations which are very much similar to the console input and output operations. It uses file streams as an interface between the programs and the files. The stream that supplies data to the program is known as input stream and the one that receives data from the program is known as output stream. In other words, the input stream extracts (or reads) data from the file and the output stream inserts (or writes) data to the file. The input operation involves the creation of an input stream and linking it with the program and the input file. Similarly, the output operation involves establishing an output stream with the necessary links with the program and the output file. Input data read data data input
Program
Disk files
data output Output data write data
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
97
CLASSES FOR FILE STREAM OPERATIONS The I/O system of C++ contains a set of classes that define the file handling methods. These include ifstream, ofstream and fstream. These classes are derived from fstreambase and from the corresponding iostream.h class as shown in Figure. These classes, designed to manage the disk files, are declared in fstream.h and therefore we must include this file in any program that uses files. Table shows the details of file operation classes. Note that these classes contain many more features. For more details, refer to the manual. ios
iostream.h file
istream
streambuf
ostream
iostream
ifstream
fstream
ofstream
filebuf
fstream.h file fstream base
Details of file stream classes Class
Contents
filebuf
Its purpose is to set the file buffers to read the write. Contains openprot constant used in the open() of file stream classes. Also contains close() and open() as members.
fstreambase
Provides operations common to the file streams. Serves as a base for fstream. ifstream and ofstream classes. Contains open() and close() functions.
ifstream
Provides input operations. Contains opens() with default input mode. Inherits the functions get(), getline(), read(), seekg() and tellg() functions from istream.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
98
ofstream
Provides output operations. Contains open() with default output mode. Inherits put(), seekp(), tellp(), and write() functions from ostream.
fstream
Provides support for simultaneous input and output operations. Contains open() with default input mode. Inherits all the functions from istream and ostream classes through iostream.
OPENING AND CLOSING A FILE If we want to use a disk file, we need to decide the following things about the file and its intended use: 1. Suitable name for the file. 2. Data type and structure. 3. Purpose. 4. Opening method. The filename is a string of characters that make up a valid filename for the operating system. If may contain two parts, a primary name and an optional period with extension. Examples: Input.data Test.doc INVENT.ORY student salary OUTPUT As stated earlier, for opening a file, we must first create a file stream and then link it to the filename. A file stream can be defined using the classes ifstream. ofstream, and fstream that are contained in the header the fstream.h. The class to be used depends upon the purpose, whether we want to read data from the file or write data to it. A file can be opened in two ways: 1. Using the constructor function of the class. 2. Using the member function open() of the class. The first method is useful when we use only one file in the stream. The second method is used when we want to manage multiple files using one stream. Opening Files Using Constructor We know that a constructor is used to initialize an object while it is being created. Here, a filename is used to initialize the file stream object. This involves the following steps: 1. Create a file stream object to manage the stream using the appropriate class. That is, the class ofstream is used to create the output stream and the class ifstream to create the input stream. 2. Initialize the file object with the desired filename. For example, the following statement opens a file named “results” for output. ofstream outfile(“results”); //output only This creates outfile as an ofstream object that manages the output stream. This object can be any valid C++ name such as o_file, myfile or fout. This statement also open the file results and attaches it to the output stream outfile.
Disk Output stream results file outfile
Program Input stream
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621data file infile
OBJECT ORIENTED PROGRAMMING
99
Similarly, the following statement declares infile as an ifstream object and attaches it to the file data for reading (input). ifstream infile(“data”); /input only The program may contain statements like: outfile << “TOTAL”; outfile << sum; infile >> number; infile >> string; Program 1 put data outfile Salary file Program 2 get data infile
We can also use the same file for both reading and writing data as shown in Figure. The programs would contain the following statements: Program1 .... .... ofstream outfile(“salary”) //creates outfile and connects //”salary”to it .... .... Program2 .... .... ifstream infile(“salary”) //creates infile and connects //”salary”to it .... .... connection with a file is closed automatically when the stream object expires (when the program terminates). That is, when the program1 is terminated, the salary file is disconnected from the outfile stream. Similar action takes place when the program2 terminates. Instead of using two programs, one for writing data (output) and another for reading data (input), we can use a single program to do both the operations on a file. Example. .... .... outfile, close(); //Disconnect salary from outfile ifstream infile(“salary”); //and connect to infile .... .... infile.close(); //Disconnect salary from infile Allthough we have used a single program, we created two file stream objects, outfile (to put data to the file) and infile (to get data from the file), Note that the use of a statement like outfile.close();
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
100
disconnects the file salary from the output stream outfile. Remember, the object outfile still exists and the salary file many again be connected to outfile later or to any other stream. In this example, we are connecting the salary file to infile stream to read data. #include <fstream.h> main() { ofstream outf(“ITEM”); //connect ITEM file to outf cout << “Enter item name:”; char name[30]; cin >> name: //get cost from key board and outf << name << “\n”; //write to file ITEM cout << “Enter item cost:”; float cost; cin >> cost; //get cost from key board and outf << cost << “\n”; //write to file ITEM outf.close(); ifstream inf(“ITEM”);
//Disconnect ITEM file from outf //and connect it to inf
inf >> name; //read name from file ITEM inf >> cost; //read cost from file ITEM cout << “\n”; cout << “Item name:” << name << “\n”; cout << “Item cost:” << cost << “\n”; inf.close(); //Disconnect ITEM from inf } caution: When a file is opened for writing only, a new file is created if there is no file of that name. If a file by that name exists already, then its contents are deleted and the file is presented as a clean file. We shall discuss later how to open an existing file for updating it without losing its original contents. Opening Files Using open( ) The function open( ) can be used to open multiple files that use the same stream object. For example, we may want to process a set of files sequentially. In such cases, we may create a single stream object and use it to open each file in turn. This is done as follows:
Example:
file-stream-class stream-object; stream-object.open (:filename”);
ofstream outfile; //Create stream (for output) outfile.open(“DATA1”); //Connect stream to DATA1 .... .... Outfile.close( ); //Disconnect stream from DATA1 outfile.open(“DATA2); //Connect stream to DATA2 .... .... Outfile.close( ); //Disconnect stream from DATA2 .... .... The above program segment opens two files in sequence for writing the data. Note that the first file is closed before opening the second one. This is necessary because a stream can be connected to only one file at a time #include <fstream.h> main() {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
101
ofstream fout; //create output stream fout.open(“country”) //connect “country” to it fout << “United States of America\n”; fout << “United Kingdom\n”; fout << “South Korea\n”; fout.close() fout.open (“capital”); fout << “Washington\n”; fout << “London\n”; fout << “Seoul\n”; fout.close(); //Reading the files const int N = 80; char line[N]; ifstream fin; fin.open(“country”);
//disconnect “country” and //connect “capital”
//disconnect “capital”
//size of line //create input stream //connect “country” to it
cout <<”contents of country file\n”; while(fin) //check end-of-file { fin.getline(line, N); //read a line cout << line; //display it } fin.close(); //disconnect “country” and fin.open(“capital”); //connect “capital” cout << “\nContents of capital file \n”; while (fin) { fin.getline(line, N); cout << line; } fin.close(); } #include <fstream.h> #include <stdlib.h>
//for exit() function
main() { const int SIZE = 80; char line[SIZE]; ifstream fin1, fin2; //create TWO input streams fin1.open(“country”); //connect country to fin1 fin2.open(“capital”); //connect capital to fin2 for (int i = 1; <=10; i++) { if(fin1.eof() != 0) { cout << “Exit from country \n”; exit(1); } fin1.getline(line, SIZE); cout << “Capital of “<< line; if(fin2.eof() !=0) { cout << “Exit from capital\n”;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
102
exit(1); } fin2.getline(line, SIZE); cout << line << “\n”; } } DETECTING END-OF-FILE Detection of the end-of-file condition is necessary for preventing any further attempt to read data from the file. This was illustrated in Program 11.2 by using the statement while(fin) There is another approach to detect the end-of-file condition. Note that we have used the following statement in Program 11.3: if(fin1.eof() ! = 0) {exit(1);}
eof() is a member function of ios class. It returns a non-zero value of the end-of-file(EOF) condition is encountered, and a zero, otherwise. Therefore, the above statement terminates the program on reaching the end of the file. MORE ABOUT OPEN( ): FILE MODES We have used ifstream and ofstream constructors and the function open( ) to create new files as well as to open the existing files. Remember, in both these methods, we used only one agrument that was the filename. However, these functions can take two arguments, the second one for specifying the file mode. The general form of the function open( ) with two arguments is:
stream-object.open(“filename”,.mode); The second argument mode (called file mode parameter) specifies the purpose for which the file is opened. How did we then open the files without providing the second argument in the previous examples? The prototype of these class member functions contain default value for the second argument and therefore they use the default values in the absence of the actual values. The default values are as follows: ios::in for ifstream functions meanings open for reading only. ios::out for ofstream functions meaning open for writing only. The file mode parameter can take one (or more) of such constants defined in the class ios. Table lists the file mode parameters and their meaning. File mode Parameters Parameter
Meaning
ios::app
Append to end-of-file
ios::ate
Go to end-of-file on opening
ios::binary
Binary file
ios::in
Open file for reading file
ios::nocreate
Open fails if the file does not exist
ios::noreplace
Open fails if the file already exists
ios::out
Open file for writing only
ios::trunc
Delete contents of the file if it exists
1. Opening a file in ios::out mode also opens it in the ios::trune mode by default.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
103
2. Both ios::app and ios::ate take us to the end of the file when it is opened. But the difference between the two parameters is that the ios::app allows us to add data to the end of the file only, while ios::ate mode permits us to add data or to modify the existing data anywhere in the file. In both the cases, a file is created by the specified name, if it does not exist. 3. The Parameter ios::app can be used only with the files capable of output. 4. Creating a stream using ifstream implies input and creating a stream using ofstream implies output. So in these cases it is not necessary to provide the mode parameters. 5. The fstream class does not provide a mode by default and therefore, we must provide the mode explicitly when using an object of fstream class. 6. The mode can combine two or more parameters using the bitwise OR operator (symbol) as shown below: fout.open(“data”, ios::app | ios;:nocreate) This opens the file in the append mode but fails to open the file if it does not exist. Each file has two associated pointers known as the file pointers. One of them is called the input pointer (or get pointer) and the other is called the output pointer (or put pointer). We can use these pointers to move through the files while reading or writing. The input pointer is used for reading the contents of a given file location and the output pointer is used for writing to a given file location. Each time an input or output operation takes place, the appropriate pointer is automatically advanced. Default Actions When we open a file in read-only mode the input pointer is automatically set at the beginning that we can read the file from the start, Similarly, when we open a file write-only mode, the existing contents are deleted and the output pointer is set at the beginning. This enables us to write to the file from the start. In case, we want to open an existing file to add more data, the file is opened in ‘append’ mode. This moves the output pointer to the end of the file (i.e. the end of the existing contents). See Figure,
Open for reading only
H
E
L
L
O
W O
R
L
D
input pointer
Open in append mode (for writing more data)
H
E
L
L
O
W O
R
L
D
output pointer
Open for writing only output pointer
Functions for Manipulation of File Pointers All the actions on the file pointers as shown in Fig. 11.7. take place automatically by default. How do we then move a file pointer to any other desired position inside the file? This is possible only if we can take control of the movement of the file pointers ourselves. The file stream classes support the following functions to manage such situations: seekg( ) Moves get pointer (input) to a specified location. seekp( ) Moves put pointer (output) to a specified location. tellg ( ) Gives the current position of the get pointer. tellp( ) Gives the current position of the put pointer. For example, the statement
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
104
infile.seekg(10); moves the file pointer to the byte number 10, Remember, the bytes in a file are numbered beginning th from zero. Therefore, the pointer will be pointing to the 11 byte in the file. Consider the following statements: ofstream fileout; fileout.open(“hello”, ios::app); int p = fileout.tellp( ); On execution of these statements, the output pointer is moved to the end of the file “hellow” and the value of P will represent the number of bytes in the file.
Specifying the Offset We have just now seen how to move a file pointer to a desired location using the ‘seek’ functions. The argument to these functions represent the absolute position in the file. file start
end
outfile.seekp(m);
m bytes ‘Seek’ functions seekg( ) and seekp( ) can also file be pointer used with two arguments as follows:
seekg(offset, refposition); seekp(Offset, refposition); The parameter offset represents the number of bytes the file pointer is to be moved from the location specified by the parameter refposition. The refposition takes one of the following three constants defined in the ios class: ios::beg ios::cur ios::end
start of the file current position of the pointer End of the file
The seeg( ) function moves the associated file’s ‘get’ pointer while the seekp( ) function moves the associated file’s ‘put’ pointer. Table 11.3 lists some sample pointer offset calls and their actions. fout is an ofstream object.
Pointer offset calls Seek call
Action
fout.seekg(o, ios::beg);
Go to the start
fout.seekg(o, ios::cur);
Stay at the current position
fout.seekg(o, ios::end);
Go to the end of the file
fout.seekg(m, ios::beg);
Move to(m+1)th byte in the file
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
105
fout.seekg(m, ios::cur);
Go forward by m bytes from the current position
fout.seekg(-m, ios::cur);
Go backward by m bytes from the current position
fout.seekg(-m, ios::end);
Go backward by m bytes from the end
SEQUENTIAL INPUT AND OUTPUT OPERATIONS The file stream classes support a number of member functions for performing the input and output operations on files. One pair of functions, put( ) and get( ), are designed for handling a single character at a time. Another pair of functions, write( ) and read( ), are designed to write and read blocks of binary data. put( ) and get( ) Functions The function put ( ) writes a single character to the associated stream. Similarly, the function get( ) reads a single character from the associated stream. The program requests for a string. On receiving the spring, the program writes it, character by character, to the file using the put( ) function in a for loop. Note that the length of the string is used to terminate the for loop. The program then displays the contents of the file on the screen. It uses function get( ) to fetch a character from the file and continues to do so until the end-of-file condition is reached. The character read from the file is displayed on the screen using the operator <<. #include <fstream.h> #include <string.h> main( ) { char string[80]; cout << “Enter a string \n”; cin >> string; int len = strlen (string); fstream file; //input and output stream file.open(“TEXT”, ios::in | ios :: out); for (int i = 0; i < len; i++) file.put(string[i]); //put a charcter to file file.seekg(0); char ch; while(file) { file.get(ch); cout << ch; }
//go to the start
//get a character from file //display it on screen
} Note that we have used an fstream object to open the file. Since an fstream object can handle both the input and output simultaneously, we have opened the file in ios::in|ios::out mode. After writing the file, we want to read the entire file and display its contents. Since the file pointer has already moved to the end of the file, we must bring it back to the start of the file. This is done by the statement file.seekg(0); write( ) and read ( ) Functions The functions write( ) and read( ), unlike the functions put( ) and get( ), handle the data in binary form. This means that the values are stored in the disk file in the same format in which they are stored in the internal memory. Figure shows how an int value 2094 is stored in the binary and character formats. An int takes two bytes to store its value in the binary form, irrespective of its size. But a 4-digit int will take four bytes to store it in the character form. The binary format is more accurate for storing the numbers as they are stored in the exact internal representation. There are no conversions while saving the data and therefore saving is much faster. The binary input and output functions takes the following form: 2 bytes
Binary format 00001010 00100010 FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
Character format
2
5
106
9
4
4 bytes
Binary and character formats of an integer value These functions take two arguments. The first is the address of the variable v, and the second is the length of the variable in bytes. The address of the variable must be cast to type char* (i.e. pointer to character type). Program 11.5 illustrates how these two functions are used to save an array of float numbers and then recover them for display on the screen. UPDATING A FILE : RANDOM ACCESS Updating is a routine task in the maintenance of any data file. The updating would include one or more of the following tasks: Displaying the contents of a file. Modifying an existing item. Adding a new item. Deleting an existing item. These actions require the file pointers to move to a particular location that corresponds to the item/object under consideration. This can be easily implemented if the file contains a a collection of items/objects of equal lengths. In such cases, the size of each object can be obtained using the statement. int object_length = sizeof(object); Then, the location of a desired object, say the mth object, may be obtained as follows: int location = m* object_length; The location gives the byte number of the first byte of the mth object. Now, we can set the file pointer to reach this byte with the help of seekg() or seekp( ). We can also find out the total number of objects in a file using the object_length as follows: int n = file_size/object_length; The file_size can be obtained using the function tellg( ) or tellp( ) when the file pointer is located at the end of the file. 1) Adds a new item to the file. 2) Modifies the details of an item. 3) Displays the contents of the file. #include <fstream.h> #include <iomanip.h> class INVENTORY { char name[10]; int code; float cost; public: void getdata(void) { cout << “Enter name: “; cin >> name; cout << “Enter code: “; cin >> code; cout << “Enter cost: “; cin >> cost; } void putdata(void) { cout << setw(10) << name << setw(10) << code << setprecision(2) << setw(10) << cost << end1; } }; //End of class definition
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
107
main( ) { INVENTORY item; fstream inoutfile; //input/output stream inoutfile.open(“STOCK.DAT”, ios:: ate|ios::in| ios::out | ios::binary); inoutfile.seekg(0, ios::beg); //go to start while (inoutfile.read((char *) & item, sizeof item))\ item.putdata(); } inoutfile.clear(); //turn of EOF flag
{
/*..........ADD ONE MORE ITEM................*/ cout << “\nADD IN ITEM\n”; item.getdata(); char ch; cin.get(ch); inoutfile.write((char *) & item, sizeof item); //............Display the appended file inoutfile.seekg(0); //go to the start cout << “CONTENTS OF APPENDED FILE \n”; while (inoutfile.read((char *) & item, sizeof item)) { item.putdata(); } //..............Find number of objects in the file int last = inoutfile.tellg(); cout << “Number of objects = “ << n << “\n”; while(inoutfile.read((char *) & item, size of item)) { item.putdata(); //..............MODIFY THE DETAILS OF AN ITEM .....*/ cout << “Enter object number to be updated \n”; cin >> object; cin.get (ch); int location = (object-1) * sizeof(item); if(inoutfile.eof()) inoutfile.clear(); inoutfile.seekp(location); cout << “Enter new values of the object \n”; item.getdata(); cin.get(ch); inoutfile.write((char
*)&
item,
sizeof
item)
<<
/*..........SHOW UPDATED FILE .................*/ inoutfile.seekg(0); //go to the start cout << “CONTENTS OF UPDATED FILE \n”; while(inoutfile.read((char *) & item, sizeof item)) { item.putdata(); } inoutfile.close(); }
//End of main
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
flush;
OBJECT ORIENTED PROGRAMMING
108
ERROR HANDLING DURING FILE OPERATIONS So far we have been opening and using the files for reading and writing on the assumption that everything is fine with the files. This may not be true always. For instance, one of the following things may happen when dealing with the files: 1. 2. 3. 4. 5. 6.
A file which we are attempting to open for reading does not exist. The file name used for a new file may already exist. We many attempt an invalid operation such as reading past the end-of-file. There may not be any space in the disk for storing more data. We may use an invalid file name. We may attempt to perform an operation when the file is not opened for that purpose. The C++ file streams inherits a ‘stream-state’ member from the class ios. This member records information on the status of a file that is being currently used. The stream state member uses bit fields to store the status of the error conditions stated above. The class ios supports several member functions that can be used to read the status recorded in a file stream. These functions along with their meanings are listed in Table. Error handling functions Function
Return value and meaning
eof()
Returns true(non-zero value) if end-of-life is encountered while reading; otherwise returns false(zero).
fail()
Returns true when an input or output operation has failed.
bad() Returns true an invalid operation is attempted or any unrecoverable error has occurred. However, if it is false, it may be possible to recover from any other error reported and continue operation.
good( )
Returns true no error has occurred. This means, all the above functions are false. For instance, if file.good() is true, all is well with the stream file and we can proceed to perform I/O operations. When it returns false, no further operations can be carried out.
These functions may be used in the appropriate in a program to locate the status of a file stream and thereby to take the necessary corrective measures, Example: .... .... ifstream infile; infile.open(“ABC”); while(linfile.fail()) { .... . . . . (process the file) .... } if(linfile.eof( )) { . . . . (terminate program normally) } else if(infile.bad( )) {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
109
. . . . (report fatal error) } else { infile.clear(); //clear error state .... .... } .... .... The function clear ( ) (which we used in the previous section as well) resets the error state so that further operations can be attempted. Remember that we have already used statements such as while(infile) { .... .... } and while(infile.read(....)) { .... .... } Here, infile becomes false (zero) when end of the file is reached (and eof( ) becomes true). COMMAND-LINE ARGUMENTS Like C, C++ too supports a feature that facilities the supply of arguments to the main( ) function. These arguments are supplied at the time of invoking the program. They are typically used to pass the names of data files. Example: C> exam data results Here, exam is the name of the file containing the program to be executed, and data and results are the filenames passed to the program as command-line arguments. The command-line arguments are typed by the user and are delimited by a space. The first argument is always the filename (command name) and contains the program to be executed. How do these arguments get into the program? The main( ) functions which we have been using up to now without any arguments can take two arguments as shown below: main(int argc, char * argv[]) The first argument argc (known as argument counter) represents the number of arguments in the command line. The second argument argv (known as argument vector) is an array of char type pointers that point to the command line arguments. The size of this array will be equal to the value of argc. For instance, for the command line C > exam data results the value of argc would be 3 and the argv would be an array of three pointers to strings as shown below: argv[0] exam argv[1] data argv[2] results Note that argv[0] always represents the command name that invokes the program. The character pointers argv[1] and argv[2] can be used as file names in the file opening statements as shown below: .... .... infile.open(argv[1]); ....
//open data file for reading
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING .... outfile.open(argv[2]); .... ....
110
//open results file for writing
The command line is test ODD EVEN The program creates two files called ODD and EVEN using the command-line arguments and a set of numbers stored in an array are written to these files. Note that the odd numbers are written to the file ODD and the even numbers are written to the file EVEN. The program then displays the contents of the files. #include <fstream.h> #include <stdlib.h> main(int argc, char * argv[]) { nt number[9] = {11,22,33,44,55,66,77,88,99}; if(argc !=3) { cout << “argc =” << argc << “\n”; cout << “Error in arguments \n”; exit(1); } ofstream fout1, fout2; fout1.open(argv[1]); if(fout1.fail()) { cout << “could not open the file” << argv[1] << “\n”; exit(1); } fout2.open(argv[2]); if(fout2.fail()) { cout << “could not open the file” << argv[2] << “\n”; exit(1); } for(int i = 0; i < 9; i++) { if(number[i] % 2 == 0) fout2 << number[i] <<” “;//write to EVEN file else fout1 << number[i] <<” “;//write to ODD file } fout1.close(); fout2.close(); ifstream fin; char ch; for (i = 1; i <argc; i++) { fin.open(argv[i]); cout << “Contents of “ << argv[i] << “\n”; do { fin.get(ch); //read a value cout << ch; //display it } while(fin);
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
111
cout << “\n\n”; fin.close(); } } TEMPLATES AND EXCEPTION HANDLING Templates and exception handling are the two new features added recently to C++. Templates enables us to define generic classes and exception handling provides a mechanism to identify and manage certain “disastrous” error conditions during the execution of a program. TEMPLATES We can define templates for both classes and functions. A template can be used to create family of classes or functions. For example, a class template for an array class would enable us to create arrays of various data types such as int array and float array. Similarly, we can define a template for a function, say mul( ) that would help us create various versions of mul( ) for multiplying int, float and double type values. A template can be considered as a kind of macro. When an object of a specific type is defined for actual use, the template definition for that class is substituted with the required data type. Since a template is defined with a parameter the would be replaced by the specified data type at the time of actual use of the class or function, the templates are sometimes called parameterized classes or functions.
CLASS TEMPLATES Consider a vector class defined as follows: class vector { int* v; int size; public: vector(int m) //create a null vector { V=new int [size = m]; for(int i = 0; i < size; i++) v[i] = 0; } vector(int * a) //create vector from an array { for (int i = 0; i < size; i++) v[i] = a[i]; } int sum = 0; for(int i = 0; i < size; i++) sum + = this -> v[i] * y.v[i]; return sum; } }; The vector class can store an array of int numbers and perform the scalar product of two vectors as shown below: main ( ) { int x[3] = {1,2,3}; int y[3] = {4,5,6}; vector v1(3)l vector v2(3);
//creates a null vector of 3 integers
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING v1 = x; v2 = y;
112
//creates v1 from the array x
int R = v1 * v2; cout << â&#x20AC;&#x153;R =â&#x20AC;? R; } Now suppose we want to define a vector that can store an array of float values. We can do this by simply replacing the appropriate int declarations with float in the vector class. This means that we have to redefine the entire class all over again. Assume that we want to define a vector class with the data type as a parameter and then use this class to create a vector of any data type instead of defining a new class every time. The template mechanism enables us to achieve this goal. As mentioned earlier, templates allow us to define generic classes. It is a simple process to create a generic class using a template with an anonymous type. The general format of a class template is:
template<class T> class classname { //........ //class member specification //with anonymous type T //wherever appropriate //............ }; The template definition of vector class shown below illustrates the syntax of a template: template < class T > class vector { T * v; //type T vector int size; public: vector(int m) { v = new T [size = m]; for(int i = 0; i < size; i++) v[i] = 0; } vector(T* a) { for(int i = 0; i < size, i++) V[i] = a[i]; } T operator*(vector & y) { T sum = 0; for (int i = 0; i < size; i++) sum += this -> v[i]* y.v[i] return sum; } };
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
113
Note that the class template definition is very similar to an ordinary class definition except the prefix template < class T > and the use of Type T. This prefix tells the compiler that we are going to declare a template and use T as a type name in the declaration. Thus, vector has become a parameterized class with the type T as its parameter. T may be substituted by any data type including the user-defined types. Now, we can create vectors for holding different data types. Example: vector <int> v1(10); //10 element int vector vector <float> v2(25); //25 element float vector Note that the type T may represent a class name as well. Example: vector <complex> v3(5); //vector of 5 complex number A class created from a class template is called a template class. The syntax for defining an object of a template class is:
classname <type> objectname (arglist); This process of creating a specific class from a class template is called instantiation. The compiler will perform the error analysis only when an instantiation takes place. It is, therefore, advisable to create and debug an ordinary class before converting it into a template. FUNCTION TEMPLATES Like class templates, we can also define function templates that could be used to create a family of functions with different argument types. The general format of a function template is:
template<class T> returntype functionname (arguments of type T) { //............................. //Body of function //with type T //wherever appropriate //............ } The function template syntax is similar to that of the class template except that we are defining functions instead of classes. We must use the template parameter T as and when necessary in the function body and in its argument list. The following example declares a swap( ) function template that will swap two values of a given type of data.
template < class T > void swap (T&x, T&y) { T temp = x; x = y; y = temp; } This essentially declares a set of overloaded functions, one for each type of data. We can invoke the swap( ) function like any ordinary function. For example, we can apply the swap( ) function as follows:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
114
void f(int m, int n, float a, float b) { swap(m,n); //swap two integer values swap(a,b); //swap two float values //.............. }
This will generate a swap( ) function from the function template for each set of argument types. Another function often used is sort( ) for sorting arrays of various types such as int and double. The following example shows a function template for bubble sort: template < class T > bubble(Ta[], int n) { for(int i = 0; i < n – 1; i++) for(int j = n – 1; i < j; j--) if(a[i] < a[j-1]) { T temp = v[j]; v[j] = v[j-1]; v[j-1] = temp; } } Note that the swapping statements T temp = v[j]; v[j] = v[j-1]; v[j-1] = temp; may be replaced by the statement swap( v[j], v[j-1]); where swap ( ) has been defined as a function template. Here is another example where a function returns a value. template < class T > T max (T x, T y) { return x > y ? x:y’ } A function generated from a function template is called a template function. A template function may be overloaded either by template functions or ordinary functions of its name. In such cases, the overloading resolution is accomplished as follows: 1. Call any ordinary function that has an exact match. 2. Call a template function that could be created with an exact match. 3. Try normal overloading resolution to ordinary functions and call the one that matches. An error is generated if no match is found. Note that no automatic conversions are applied to arguments on the template functions. MEMBER FUNCTION TEMPLATES When we created a class template for vector, all the member functions were defined as inline which was not necessary. We could have defined them outside the class as well. But remember that the
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
115
member functions of the template classes themselves are parameterized by the type argument (to their template classes) and therefore these functions must be defined by the function templates. It takes the following general form:
template<class T> returntype classname <T>|| functionalname(arglist) { //............................. //Function body //with type T //................................. } The vector class template and its member functions are redefined as follows: //Class template ................. template < class T > class vector { T * v; int size; public: vector (int m); vector (T* a); T operator* (vector & y); }; //Member function templates ........... template< class T> vector<T> :: vector(int m) { v = new T [size = m]; for (int i = 0; i < size: i++) v[i] = 0; } template<class T> vector<T> :: vector(T * a) { for (int i = 0; i <size; i++) v[i] a [i]; } template<class T> Tvector<T> :: operator*(vector & y) { T sum = 0; for (int i = 0; i < size; i++) sum + = this -> v[i]* y.v[i]; return sum; }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
116
TEMPLATE ARGUMENTS
A template can have multiple arguments. That is, in addition to the type argument T, we can also use other arguments such as strings, function names, constant expressions and built-in types. Consider the following example: template<class T, int size> class array { T a[size]; //automatic array initialization //.............. //.............. }; The template supplies the size of the array as an argument. This implies that the size of the array is known to the compiler at the compile time itself. The argument must be specified whenever a template class is created. Example: array<int, 10> a1; array<float, 5> a1; array<char, 20> a3;
//array of 10 integers //array of 5 floats //string of size 20
The size is given as an argument to the template class. Compare this with the creation of the template class vector where the size is given as an argument to the object.
EXCEPTION HANDLING
Exception handling is the latest feature added to ANSI C++. Exceptions refer to unusual conditions in a program. They could be errors that cause the programs to fail or certain conditions that lead to errors. When a program encounters an exceptional condition, it is important that it is dealt with. Exceptions are of two kinds, namely, synchronous exceptions and asynchronous exceptions. Errors such as “out-of-range index” and “over-flow” belong to the synchronous type exceptions. The errors that are caused by events beyond the control of the program (such as keyboard interrupts) are called asynchronous exceptions. The proposed exception handling mechanism in C++ is designed to handle only synchronous exceptions. The purpose of the exception handling mechanism is to provide means to detect and report an “exceptional circumstance” so that appropriate action can be taken. The mechanism suggests a separate error handling code that performs the following tasks: 1. 2. 3. 4.
Find the problem (Hit the exception). Inform that an error has occurred (Throw the exception). Receive the error information (Catch the exception). Take corrective actions (Handle the exception).
The error handling code basically consists of two segments, one to detect errors and to throw exceptions and the other to catch the exceptions and to take appropriate actions. SYNTAX OF EXCEPTION HANDLING CODE C++ uses three new keywords namely, throw, try and catch to handle exceptions. When a function returns using the exception handling mechanism. It is referred to as throwing an exception. The keyword throw implements this “return” activity. The keyword try prefaces a block of statements with may generate exceptions. A catch block defined by the keyword catch ‘catches’ the
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
117
exceptions ‘thrown’ by throw and handles them appropriately. The relationship of these three blocks are shown in Fig. A.1. The “try” block code normally invokes a function that detects an exception. The function which is in the “throw” block returns (“throws”) the control to the “catch” block. The catch block may have more than one catch statements, each corresponding to a particular type of exception. For example, if the throw block is likely to throw two exceptions, the catch block will have two catch statements, one for each type of exception. Each catch statement is called an exception handler.
The function that throws the exceptions indicates the statement to be executed. somewhat similar to a switch statement.
It is
throw Block Function that causes exception Invoke
try Block Throw
Invoke a function that causes exception
Fig.A.1. Exception handling mechanism catch Block The example below illustrates the syntax handling mechanism. We again use catch 1of exceptionException any array class for the sake of simplicity. handlers catch 2 class array catch 3 { int *a; int size; public: enum {M = 1000); class SIZE { }; class RANGE { }; array(int SIZE); int & operator(int i); }; array || array(int size) { if(size < 0 || size > M) throw SIZE( ); //................. //................. } int & array || operator[](int i) { if(i < 0 || i > = size) throw RANGE( ); else
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
118
return a[i]; } void func( ) { try { //use of array objects } catch(array :: SIZE) { //size error handler } catch(array :: RANGE) { //range error handler } //.................... //.................... }
The classes SIZE and RANGE are created especially for use in exception handling. If the SIZE object thrown, we end up in the size error handler and if the RANGE object is thrown, we end up in the range error handler.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
119
Unit IV CLASS, OBJECTS AND METHODS Java is a true object-oriented language and therefore the underlying structure of all java programs is classes. Anything we wish to represent in a java program must be encapsulated in a class that defines the state and behaviour of the basic program components known as objects. Classes create objects and objects use methods to communicate between them. Classes provide a convenient method for packing together a group of logically related data items and functions that work on them. In java, the data items are called fields and the functions are called methods. Calling a specific method in an object is described as sending the object a message. A class is essentially a description of how to make an object that contains fields and methods. It provides a sort of template for an object and behaves like a basic data type such as int. It is therefore important to understand how the fields and methods are defined in a class and how they are used to build a java program that incorporates the basic OOP concepts such as encapsulation, inheritance and polymorphism. DEFINING A CLASS A class is a user-defined data type with a template that serves to define its properties. Once the class type has been defined, user can create â&#x20AC;&#x153;variablesâ&#x20AC;? of that type using declarations that are similar to the basic type declarations. In java, these variables are termed as instances of classes, which are the actual objects. The basic form of a class definition is:
class classname [extends superclassname] { [ variable declaration; ] [ methods declaration; ] } Everything inside the square brackets is optional. This means that the following would be a valid class definition: Class Empty { } ADDING VARIABLES Data is encapsulated in a class by placing data fields inside the body of the class definition. These variables called instance variables because they are created whenever an object of the class is instantiated. We can declare the instance variables exactly the same way as we declare local variables.
Example: class Rectangle { int length; int width; } The class Rectangle contains two integer type instance variables. It is allowed to declare them in one line as int length, width; Remember these variables are only declared and therefore no storage space has been created in the memory. Instance variables are also known as member variables. ADDING METHODS
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
120
A class with only data fields (and without methods that operate on that data) has no life. The objects created by such a class cannot respond to any messages. We must therefore add methods that are necessary for manipulating the data contained in the class. Methods are declared inside the body of the class but immediately after the declaration of instance variables. The general form of a method declaration is
type methodname (parameter-list) { method-body; }
Method declarations have four basic parts: The name of the method (method name) The type of the value the method returns (type) A list of parameters (parameter-list) The body of the method The type specifies the type of value the method would return. This could be a simple data type such as int as well as any class type. It could even be void type, if the method does not return any value. The method name is a valid identifier. The parameter list is always enclosed in parentheses. This list contains variable names and types of all the values we want to give to the method as input. The variables in the list are separated by commas. In the case where no input data are required, the declaration must retain the empty parentheses. Examples: (int m, float x, float y) / / Three parameters ( ) / / Empty list The body actually describes the operations to be performed on the data. Let us consider the Square class again and add a method getData( ) to it. class Square { int length; int widht; void getData (int x, int y ) { length = x ; width = y ; } } Note that the method has a return type of void because it does not return any value. We pass two integer values to the method which is then assigned to the instance variables length and width. The getData method is basically added to provide values to the instance variables. Notice that we are able to use directly length and width inside the method. CREATING OBJECTS An object in Java is essentially a block of memory that contains space to store all the instance variables. Creating an object is also referred to as instantiating an object. Objects in Java are created using the new operator. The new operator creates an object of the specified class and returns a reference to that object. Here is an example of creating an object of type Rectangle Square rect1 ; // declare rect1 = new Square( ); // instantiate The first statement declares a variable to hold the object reference and the second one actually assigns the object reference to the variable.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
121
ACCESSING CLASS MEMBERS After creating objects one should assign values to these variables in order to use them in our program. All variables must be assigned values before they are used. Since we are outside the class, we cannot access the instance variables and the methods directly. To do this, we must use the concerned object and the dot operator as shown below:
objectname. variable name objectname.methodname (parameter-list); Here object name is the name of the object, variable name is the name of the instance variable inside the object that we wish to access, method name is the method that we wish to call, and parameter-list is a comma separated list of “actual values” (or expressions) that must match in type and number with the parameter list of the method name declared in the class. CONSTRUCTORS We know that all objects that are created must be given initial values. We have done this earlier using two approaches. The first approach uses the dot operator to access the instance variables and then assigns values to them individually. It can be a tedious approach to initialize all the variables of all the objects. The second approach takes the help of a method like getData to initialize each object individually using statements like, rect1. getData (15, 10); It would be simpler and more concise to initialize an object when it is first created. Java supports a special type of method, called constructor, that enables an object to initialize itself when it is created. Constructors have the same name as the class itself. Secondly, they do not specify a return type, not even void. This is because they return the instance of the class itself. METHODS OVERLOADING In java, it is possible to create methods that have the same name, but different parameter lists and different definitions. This is called method overloading. Method overloading is used when objects are required to perform similar tasks but using different input parameters. When we call a method in a object, java matches up the method name first and then the number and type of parameters to declare which one of the definitions to execute. This process is known as polymorphism: To create an overloaded method, all we have to do is to provide several different method definitions in the class, all with the same name, but with different parameter lists. The different may either be in the number or type of arguments. That is, each parameter list should be unique. Note that the method’s return type does not play any role in this. Here is an example of creating an overloaded method. STATIC MEMBERS We have seen that a class basically contains two sections. One declares variable and the other declares methods. These variables and methods are called instance variables and instance methods. This is because every time the class is instantiated, a new copy of each of them is created. They are accessed using the objects (with dot operator). Let us assume that we want to define a member that is common to all the objects and accessed without using a particular object. That is, the member belongs to the class as a whole rather than the objects created from the class. Such members can be defined as follows: static int count ; static int max (int x, int y); The members that are declared static as shown above are called static members. Since these members are associated with the class itself rather than individual objects, the static variables and static methods are often referred to as class variables and class methods in order to distinguish them from their counterparts, instance variables and instance methods. Static variables are used when we want to have a variable common to all instances of a class. One of the most common examples is to have a variable that could keep a count of how many objects of a class have been created. Remember, Java creates only one copy for a static variable which can be used even if the class is never actually instantiated. Like static variables, static methods can be called without using the objects. They are also available for use by other classes. Methods that are of general utility but do not directly affect an
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
122
instance of that class are usually declared as class methods. Java class libraries contain a large number of class methods. For example, the Math class of Java library defines many static methods to perform math operations that can be used in any program. We have used earlier statements of the types float x = Math.sqrt (25.0); The method sqrt is a class method (or static method) defined in Math class. INHERITANCE: EXTENDING A CLASS Reusability is yet another aspect of OOP paradigm. It is always nice if we could reuse something that already exists rather than creating the same all over again. Java supports this concept. Java classes can be reused in several ways. This is basically done by creating new classes, reusing the properties of existing ones. The mechanism of deriving a new class from an old one is called inheritance. The old class is known as the base class or super class or parent class and the new one is called the subclass or derived class or child class. The inheritance allows subclasses to inherit all the variables and methods of their parent classes. Inheritance may take different forms: Single inheritance (only one super class) Multiple inheritance (several super classes) Hierarchical inheritance (one super class, many subclasses) Multilevel inheritance (Derived from a derived class) These forms of inheritance are shown in Fig. 8.3. Java does not directly implement multiple inheritance. However, this concept is implemented using a secondary inheritance path in the form of interfaces. Defining a Subclass A subclass is defined as follows:
class subclassname extends superclassname { variables declaration ; methods declaration ; } The keyword extends signifies that the properties of the superclassname are extended to the subclassname. The subclass will now contain its own variables and methods as well those of the superclass. This kind of situation occurs when we want to add some more properties to an existing class without actually modifying it.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
123
A
B
C
B
(a) Single inheritance
D
(b) Hierarchical inheritance
A
A
B
B
C
(c) Multilevel inheritance
(d) Multiple inheritance
Subclass Constructor A subclass constructor is used to construct the instance variables of both the subclass and the superclass. The subclass constructor uses the keyword super to invoke the constructor method of the superclass. The keyword super is used subject to the following conditions. Super may only be used within a subclass constructor method The call to superclass constructor must appear as the first statement within the subclass constructor The parameters in the super call must match the order and type of the instance variable declared in the superclass. Multilevel Inheritance A common requirement in object-oriented programming is the use of a derived class as a super class. Java supports this concept and uses it extensively in building its class library. This concept allows us to build a chain of classes as shown in Fig
Grandfather
Father
Child
A
Superclass
A
Intermediate superclass
A
Subclass
Multilevel inheritance
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
124
The class A serves as a base class for the derived class B which in turn serves as a base class for the derived class C. The chain ABC is known as inheritance path. A derived class with multilevel base classes is declared as follows. class A { ............ ............ } Class B extends A // First level { ............ ............ } class C extends B // Second level { ............ ............ } This process may be extended to any number of levels. The class C can inherit the members of both A and B. Hierarchical Inheritance Another interesting application of inheritance is to use it as a support to the hierarchical design of a program. Many programming problems can be cast into a hierarchy where certain features of one level are shared by many other below the level. As an example, Fig. 8.6 shows a hierarchical classification of accounts in a commercial bank. This is possible because all the accounts posses certain common features. OVERRIDING METHODS We have seen that a method defined in a super class is inherited by its subclass and is used by the objects created by the subclass. Method inheritance enables us to define and use methods repeatedly in subclasses without having to define the methods again in subclass. However, there may be occasions when we want an object to respond to the same method but have different behaviour when that method is called. That means, we should override the method defined in the superclass. This is possible by defining a method in the subclass that has the same name, same arguments and same return type as a method in the superclass. Then, when that method is called, the method defined in the subclass in invoked and executed instead of the one in the superclass. This is known as overriding. FINAL VARIABLES AND METHODS All methods and variables can be overridden by default in subclasses. If we wish to prevent the subclass from overriding the members of the superclass, we can declare them as final using the keyword final as a modifier. Example: final int SIZE = 100; final void showstatus( ) {...........} Making a method final ensures that the functionality defined in this method will never be altered in any way. Similarly, the value of a final variable can never be changed. Final variables, behave like class variables and they do not take any space on individual objects of the class. FINAL CLASSES Sometimes we may like to prevent a class being further subclassed for security reasons. A class that cannot be subclassed is called a final class. This is achieved in Jaga using the keyword final as follows : final class Aclass {..........} final class Bclass extends someclass {......} Any attempt to inherit these classes will cause an error and the compiler will not allow it. Declaring a class final prevents any unwanted extensions to the class. It also allows the compiler to perform some optimisations when a method of a final class is invoked.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
125
FINALIZER METHODS We have seen that a constructor method is used to initialize an object when it s declared. This process is known as initialization. Similarly, Java supports a concept called finalization. Which is just opposite to initialization. We know that Java run-time is an automatic garbage collecting system. It automatically frees up the memory resources used by the objects. But objects may hold other non-object resources such as file descriptors or window system fonts. The garbage collector cannot free these resources. In order to free these resources we must use a finalizer method. This is similar to destructors in C++. The finalizer method is simply finalize( ) and can be added to any class. Java calls that method whenever it is about to reclaim the space for the object. The finalize method should explicitly define the tasks to be performed. ABSTRACT METHODS AND CLASSES We have seen that by making a method final we ensure that the method is not redefined in a subclass. That is, the method can never be subsclassed. java allows us to do something that is exactly opposite to this. That is, we can indicate that a method must always be redefined in a subclass, thus making overriding compulsory. This is done using the modifier keyword abstract in the method definition. Example: abstract class Shape { ........... ........... abstract void draw( ); ........... ........... } When a class contains one or more abstract method, it should also be declared abstract as shown in the example above. While using abstract class, we must satisfy the following conditions: We cannot use abstract classes to instantiate objects directly. For example, Shape S = new Shape( ); is illegal because Shape is an abstract class. The abstract methods of an abstract class must be defined in its subclass. We cannot declare abstract constructors or abstract static methods. ARRAYS, STRINGS AND VECTORS STRINGS Strings manipulation is the most common part of many Java programs. Strings represent a sequence of characters. The easiest way to represent a sequence of characters in Java is by using a character array. Example:
X[0][1 ] X[0 ] X[1 ] X[2 ]
X[1][3 ]
Variable size arrays Char charArray [ ] = new char [ 4 ]; X[2][ CharArray [ 0 ] = ‘J ‘; CharArray [ 1 ] = ‘a’ ; 2] CharArray [ 2 ] = ‘v’ ; CharArray [ 3 ] = ‘a’ ; Although character arrays have the advantage of being able to query their length, they themselves are not good enough to support the range of operations we may like to perform on strings. For example, copying one character array into another might require a lot of book keeping effort. Fortunately, Java is equipped to handle these situations more efficiently.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
126
In Java, strings are class objects and implemented using two classes, namely, String and StringBuffer. A Java string is an instantiated object of the String class. Java strings, as completed to C strings, are more reliable and predictable. This is basically due to C’s lack of bounds-checking. A Java string is not a character array and is not NULL terminated. Strings may be declared and created as follows:
string stringName; stringName = new String (“ string”); Example: String firstName; firstName = new String(“Anil”); These two statements may be combimed as follows: String firstname = new String (“Anil”); Like arrays, it is possible to get the length of string using the length method of the string class. int m = firstName.length( ); Note the use of parentheses here. Java strings can be concatenated using the + operator. Examples: String fullName = name1 + name2; String city1 = “New” + “Delhi”; Where name1 and name2 are Java strings containing string constants. Another example is: System, out.println (firstName + “Kumar”); String Arrays We can also create and use arrays that contain strings. The statement String itemArray[ ] = new String[3]; will create an itemArray of size 3 to hold three string constants. We can assign the strings to the item Array element by element using three different statements or more efficiently using a for loop. String Methods The String class defines a number of methods that allow us to accomplish a variety of string manipulation tasks. Table 9.1 lists some of the most commonly used string methods, and their tasks. Program 9.3. shows the use of the method compareTo( ) to sort an array of strings in alphabetical order. Some Most Commonly Used String Methods Method Call
Task performed
s2 = s1.toLowerCase; s2 = s1.toUpperCase; s2 = s1.replace (‘x’, ‘y’); s2 = s1.trim ( );
Converts the string s1 to all lowercase Converts the string s1 to all Uppercase Replace all appearances of x with y Remove white spaces at the beginning and end of the string s1 Returns ‘true’ if s1 = s2, ignoring the case of characters Gives the length of s1 Gives nth character of s1 Returns negative if s1<s2, positive if s1 > s2, and zero if s1 is equal s2 Concatenates s1 and s2 th Gives substring starting from n character th th Gives substring starting from n character up to m th (not including m ) Creates a string object of the parameter p (simple type or object) Creates a string representation of the object p Gives the position of the first occurrence of ‘x’ in the string s1 Gives the position of ‘x’ that occurs after nth position in the string s1 Converts the parameter value to string representation
s1.equals (s2) s1.length () s1.ChartAt (n) s1.compareTo (s2) s1.concat (s2) s1.substring (n) s1.substring (n, m) String.Valueof (p) s1.toString ( ) s1.indexof (‘x’) s1.indexof(‘x’, n) String.Valueof (Variable)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
127
StringBuffer Class StringBuffer is a peer class of String. While String creates strings of fixed_length, StringBuffer creates strings of flexible length that can be modified in terms of both length and content. We can insert characters and substrings in the middle of a string, or append another string to the end. Table 9.2 lists some of the methods that are frequently used in string manipulations. Commonly Used StringBuffer Methods Method Task s1.setChartAt (n, â&#x20AC;&#x2DC;xâ&#x20AC;&#x2122;)
Modifies the nth character to x
s1.append (s2)
Appends the string s2 to s1 at the end
s1.insert (n, s2)
Inserts the string s2 at the position n of the string s1
s1.setLength (n)
Sets the length of the string s1 to n. If n<s1.length ( ) s1 is truncated. If n>s1.length ( ) zeros are added to s1
VECTORS C and C++ programmers will know that generic utility functions with variable arguments can be used to pass different arguments depending upon the calling situations. Java does not support the concept of variable arguments to a function. This feature can be achieved in Java through the use of the Vector class contained in the Java.util package. This class can be used to create a generic dynamic array known as vector that can hold objects of any type and any number. The objects do not have to be homogenous. Arrays can be easily implemented as vectors. Vectors are created like arrays as follows: Vector intVect = new Vector ( ) ; Vector list = new Vector ( 3);
// declaring without size // declaring with size
Note that a vector can be declared without specifying any size explicitly. A vector can accommodate an unknown number of items. Even, when a size is specified, this can be overlooked and a different number of items may be put into the vector. Remember, in contrast, an array must always have its size specified. Vectors possess a number of advantages over arrays. 1. It is convenient to use vectors to store objects. 2. A vector can be used to store a list of objects that may vary in size. 3. We can add and delete objects from the list as and when required. A major constraint in using vectors is that we cannot directly store simple data types in a vector; we can only store objects. Therefore, we need to convert simple types to objects. This can be done using the wrapper classes discussed in the next section. The vector class supports a number of methods that can be used to manipulate the vectors created. Important ones are listed in Table 9.3. Important Vector Methods Method Call Task performed list.addElement (item)
Adds the item specified to the list at the end
list.elementAt (10)
Gives the name of the 10 object
list.size ( )
Gives the number of objects present
list.removeElement (item)
Removes the specified item from the list
list.removeElementAt (n)
Removes the item stored in the nth position of the list
list.removeAllElements ( )
Removes all the elements in the list
list.copyInto (array)
Copies all items from list to array
th
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING list.insertElementAt (item, n)
128 Inserts the item at nth position
Program illustrates the use of arrays, strings and vectors. This program converts a string vector into an array of strings and displays the strings. Program working with vectors and arrays import java.util.*; // Importing Vector class class LanguageVector { public static void main(String args [ ]) { Vector list = new Vector ( ); int length = args.length; for (int i = 0; i < length; i++) { list.addElement (args [i]); } list.insertElementAt (“COBOL”,2); int size = list.size( ); string listArray[ ] = new String [size]; list.copyInto (listArray); System.out.println(“List of Languages:); for (int i = 0; i < size; i++) { System.out.println (listArray[i]); } } }
WRAPPER CLASSES As pointed out earlier, vectors cannot handle primitive data types like int, float, long, char, and double. Primitive data types may be converted into object types by using the wrapper classes contained in the java.lang package. Table shows the sample data types and their corresponding wrapper class types. Wrapper Classes for Converting Simple Types Simple Type
Wrapper Class
boolean
Boolean
char
character
double
Double
float
Float
int
Integer
long
Long
The wrapper classes have a number of unique methods for handling primitive data types and objects. They are listed in the following tables. Converting Primitive Numbers to Object Numbers Using Constructor Methods
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
Constructor Calling
Note:
129
Conversion Action
Inter intVal = new Integer (i);
Primitive integer to Integer object
Float FicatVal = new Float (f);
Primitive float to Float object
Double DoubleVal = new Double (d);
Primitive double to Double object
Long LongVal = new Long (1);
Primitive long to Long object
i,f,d and l are primitive data values denoting int, float, double and long data types. They may be constants or variables. Converting Object Numbers to Primitive Numbers Using typeValue( ) methods Method Calling
Conversion Action
int i = IntVal.intValue( );
Object to primitive integer
float f = FloatVal.floatValue ( );
Object to primitive float
long 1 = longVal.longValue ( );
Object to primitive long
double d = DoubleVal.doubleValue( );
Object to primitive double
Converting Numbers to Strings Using String ( )Methods Method Calling
Conversion Action
str = Integer.tostring ( i )
Primitive integer to string
str = Float.toString (f);
Primitive float to string
str = Double.toString (d);
Primitive double to string
str = Long.toString (1);
Primitive long to string
Converting String Objects to Numeric Objects Using the Static Method ValueOf( ) Method Calling
Note:
Conversion Action
DoubleVal = Double.Valueof(str);
Converts string to Double object
FloatVal = Float.ValueOf (str);
Converts string to Float object
IntVal = Integer.Valueof (str);
Converts string to Integer object
LongVal = Long.ValueOf (str);
Converts string to Long object
These numeric objects may be converted to primitive numbers using the typeValue ( ) method as shown in Table 9.6. Method Calling
Conversion Action
int i = Integer.parseInt (str);
Converts string to primitive integer
long 1 = Long.parseLong (str);
Converts string to primitive long
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
130
Interfaces: Multiple Inheritance DEFININ INTERFACES An interface is basically a kind of class. Like classes, interfaces contain methods and variables but with a major difference. The difference is that interfaces define only abstract methods and final fields. This means that interfaces do not specify any code to implement these methods and data fields contain only constants. Therefore, it is the responsibility of the class the implements an interface to define the code for implementation of these methods. The syntax for defining an interface is very similar to that for defining a class. The general form of an interface definition is:
interface InterfaceName { variable declaration; methods declaration; }
Here, Interface is the key word and InterfaceName is any valid Java variable (just like class names). Variables are declared as follows:
static final type variableName = Value; Note that all variables are declared as constants. Methods declaration will contain only a list of methods without any body statements. Example:
return-type methodName1 (parameter_list); Here is an example of an interface definition that contains two variables and one method.
interface Item { static final int code = 1001; static final String name = â&#x20AC;&#x153;Fanâ&#x20AC;?; void display ( ); }
Note that the code for the method is not included in the interface and the method declaration simply ends with a semicolon. The class that implements this interface must define the code for the method.
Another example of an interface is:
interface Area { final static float pi = 3.142F; float computer (float x, float y); void show ( ); } FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
131
EXTENDING INTERFACES Like classes, interfaces can also be extended. That is, an interface can be subinterfaced from other interfaces. The new subinterface will inherit all the members of the superinterface in the manner similar to subclasses. This is achieved using the keyword extends as shown below:
interface name 2 extends name 1 { body of name2 } For example, we can put all the constants in one interface and the methods in the other. This will enable us to use the constants in classes where the methods are not required. Example:
interface ItemConstants { int code = 1001; string name = “Fan”; } interface Item extends ItemConstants { void display ( ); }
The interface Item would inherit both the constants code and name into it. Note that the variables name and code are declared like simple variables. It is allowed because all the variable in an interface are treated as constants although the keywords final and static are not present. We can also combine several interfaces together into a single interface. Following declarations are valid:
interface ItemConstants { int code = 1001; String name = “Fan”; } interface ItemMethods { void display ( ); } interface Item extends ItemConstants, ItemMethods { ........... ........... } While interfaces are allowed to extend to other interfaces, subinterfaces cannot define the methods declared in the superinterfaces. After all, subinterfaces are still interfaces, not class. Instead, it is the rensponsibility of any class that implements the derived interface to define all the methods. Note that when an interface extends two or more interfaces, they are separated by commas. It is important to remember that an interface cannot extend classes. This would violate the rule that an interface can have only abstract methods and constants.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
132
IMPLEMENTING INTERFACES Interfaces are used as “superclasses” whose properties are inherited by classes. therefore necessary to create a class that inherits the given interface. This is done as follows:
It is
class classname implements interfacename { body of classname } Here the class classname “implements” the interface interfacename. A more general form of implementation may look like this:
class classname extends superclass implements interface1, interface2,.... } body of classname } This shows that a class can extend another class while implementing interfaces. When a class implements more than one interface, they are separated by a comma Implementation of interfaces as class types is illustrated by Program. In this program, first we create an interface Area and implement the same in two different classes, Rectangle and Circle. We create an instance of each class using the new operator. Then we declare an object of type Area, the interface class. Now, we assign the reference to the Rectangle object rect to area. When we call the compute method of area, the computer method of Rectangle class is invoked. We repeat the same thing with the Circle object. Program 1 Implementing interfaces // InterfaceTest.java interface Area // Interface defined { final static float pi = 3.14F; float compute (float x, float y); } class Rectangle implements Area // Interface impleented { public float computer (float x, float y) { return (x * y); } } class Circle implements Area // Another implementation { public float computer (float x, float y) { return (pi *x*x); } } class InterfaceTest { public static void main (String args[ ]) { Rectangle rect = new Rectangle( ); Circle cir = new Circle( ); Area area;
// Interface object
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
133
area = rect; System.out.println(“Area of Rectangle =” + area.computer(10,20)); area = cir; System.out.println(“Area of Circle = “ + area.computer(10,0)); } } Any number of dissimilar classes can implement an interface. However, to implement the methods, we need to refer to the class objects as types of the interface rather than types of their respective classes. Note that if a class that implements an interface does not implement all the methods of the interface, then the class becomes an abstract class and cannot be instantiate.
Interface
Class
A
Implementation
A
Extension
Class
B
Class
Extension
B
Extension
Interface
E Implementati on
(a) C
Class
Interface
B
Interface
D
Class
C
A
A
Implementati on Class (c)
(b)
C
Class
Interfa ce Extensio n
C (d)
B
Interface Implementati
ACCESSING INTERFACE VARIABLES on Interfaces can be used to declare a set of constants that can be used in different classes. D Clas This is similar to creating header files in C++ to contain a large number of constants. Since such s methods. The interfaces do not contain methods, there is no need to worry about implementing my constant values will be available to any class that implements the interface. The values can be used in any method, as part of any variable declaration, or anywhere where we can use a final value. Example: interface A { int m = 10; int n = 50; } class B implements A { int x = m;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
134
void methodB (int size) { .......... .......... if (size < n) .......... } } Packages : Putting Classes Together We have repeatedly stated that one of the main features of OOP is its ability to reuse the code already created. One way of achieving this is by extending the classes and implementing the interfaces.This is limited to reusing the classes within a program. What if we need to use classes from other programs without physically copying them into the program under development? This can be accomplished in Java by using what is known as packages, a concept similar to “class libraries” in other languages. Another way of achieving the reusability in Java, therefore, is to use packages. Packages we Java’s way of grouping a variety of classes and/or interfaces together. The grouping is usually done according to functionality. In fact, packages act as “containers” for classes. By organizing our classes into packages we achieve the following benefits: 1. The classes contained in the packages of other programs can be easily reused. 2. In packages, classes can be unique compared with classes in other packages. That is, two classes in two different packages can have the same name. They may be referred by their fully qualified name, comprising the package name and the class name. 3. Packages provide a way to “hide” classes thus preventing other programs or packages from accessing classes that are meant for internal use only. 4. Packages also provide a way for separating “design” from “coding”. First we can design classes and decide their relationships, and then we can implement the Java code needed for the methods. It is possible to change the implementation of any method without affecting the rest of the design. For most applications, we will need to use two different sets of classes, one for the internal representation of our program’ data, and the other for external presentation purposes. We may have to build our own classes for handling our data and use existing class libraries of designing user interfaces. Java packages are therefore classified into two types. The first category is known as Java system packages and the second is known as user defined packages. We shall consider both the categories of packages in this chapter and illustrate how to use them in our programs. SYSTEM PACKAGES Java system provides a large number of classes grouped into different packages according to functionality. Most of the time we use the packages available with the Java system. Figure 11.1 shows the functional breakdown of packages that are frequently used in the programs. Table 11.1 shows the classes the belong to each package.
Java
Java system packages
lang
util
io
awt
net
applet
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
135
Java System Packages and Their Classes Package name
Contents
java.lang
Language support classes. These are classes that Java compiler itself uses and therefore they are automatically imported. They include classes for primitive types, strings, math functions, threads and exceptions.
java.util
Language utility classes such as vectors, has tables, random numbers, date, etc.
java.io
Input/output support classes. They provide facilities for the input and output of data.
java.awt
Set of classes for implementing graphical user interface. They include classes for window, buttons, lists, menus and so on.
java.net
Classes for networking. They include classes for communicating with local computers as well as with internet servers.
java.applet
Classes for creating and implementing applets.
USING SYSTEM PACKAGES The packages are organised in a hierarchical structure as illustrated in Fig. This shows that the package named java contains the package awt, which in turn contains various classes required for implementing graphical user interface.
awt Color
Package containing awt package
Graphics
Font
Image
Package containing classes
Classes containing methods
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
136
There are two ways of accessing the classes stored in a package. The first approach is to use the fully qualified class name of the class that we want to use. This is done by using the package name containing the class and then appending the class name to it using the dot operator. For example, if we want to refer to the class Color in the awt package, then we may do so as follows: java.awt.Colour Notice that awt is a package within the package java and the hierarchy is represented by separating the levels with dots. This approach is perhaps the best and easiest one if we need to access the class only once or when we need not have to access any other classes of the package. But, in many situations, we might want to use a class in a number of places in the program or we may like to use many of the classes contained in a package. We may achieve this easily as follows:
import packagename.classname; or import packagename.*; These are known as import statements and must appear at the top of the file, before any class declarations. The first statement allows the specified class in the specified package to be imported. For example, the statement import java.awt.Color; imports the class Colour and therefore the class name can now be directly used in the program. There is no need to use the package name to qualify the class. The second statement imports every class contained in the specified package. For example, the statement import java.awt.*; will bring all classes of java.awt package. NAMING CONVENTIONS Packages can be named using the standard Java naming rules. By convention, however, packages begin with lowercase letters. This makes it easy for users to distinguish package names from class names when looking at an explicit reference to a class. We know that all class names, again by convention, begin with an uppercase letter. For example, look at the following statement: double y = java.lang.Math.sqrt(x);
package class name name
method name
This statement uses a fully qualified class name Math to invoke the method sqrt( ). Note that methods begin with lowercase letters. Consider another example: java.awt.Point pts[ ]; This statement declares an array of Point type objects using the fully qualified class name. Every package name must be unique to make the best use of packages. Duplicate names will cause run-time errors. Since multiple users work on Internet, duplicate package names are unavoidable. Java designers have recognised this problem and therefore suggested a package naming convention that ensures uniqueness. This suggests the use of domain names as prefix to the preferred package names. For example: cbe.psg.mypackage Here cbe denotes city name and psg denotes organisation name. Remember that we can create a hierarchy of packages within packages by separating level with dots. CREATING PACKAGES We have seen in detail how Java system packages are organised and used. Now, let us see how to create our own packages. We must first declare the name of the package using the package
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
137
keyboard followed by a package name. This must be the first statement in a Java source file (except for comments and white spaces). Then we define a class, just as we normally define a class. Here is an example: package firstPackage; public class FirstClass { .......... .......... (body of class) .......... }
// package declaration // class definition
Here the package name is firstPackage. The class FirstClass is now considered a part of this package. This listing would be saved as a file called FirstClass.java, and located in a directory named first Package. When the source file is compiled, Java will create a.class file and store it in the same directory. Remember that the .class files must be located in a directory that has the same name as the package, and this directory should be a subdirectory of the directory where classes that will import the package are located. To recap, creating our own package involves the following steps: 1. Declare the package at the beginning of a file using the form
package packagename; 2. 3. 4. 5.
Define the class that is to be put in the package and declare in public. Create a subdirectory under the directory where the main source files are stored. Store the listing as the classname .java file in the subdirectory created. Compile the file. This creates .class file in the subdirectory. Remember that case is significant and therefore the subdirectory name must match the package name exactly. As pointed out earlier, Java also supports the concept of package hierarchy. This is done by specifying multiple names in a package statement, separated by dots. Example: package firstPackage.secondPackage; This approach allows us to group related classes into a package and then group related packages into a larger package. Remember to store this package in a subdirectory named firstPackage\secondPackage. A Java package file can have more than one class definitions. In such cases, only one of the classes may be declared public and that class name with .java extension is the source the file name. When a source file with more than one class definition is compiled. Java creates independent .class files for those classes. ACCESSING A PACKAGE It will be recalled that we have discussed earlier that a Java system package can be accessed either using a fully qualified class name or using a shortcut approach through the import statement. We use the import statement when there are many references to a particular package or the package name is too long and unwieldy. The same approaches can be used to access the user-defined packages as well. The import statement can be used to search a list of packages for a particular class. The general form of import statement for searching a class is as follows:
import package1 [ .package2 ] [. package3]. classname;
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
138
Here package1 is the name of the top level package, package2 is the name of the package that is inside the package1, and so on. We can have any number of packages in a package hierarchy. Finally, the explicit classname is specified. Note that the statement must end with a semicolon (;). The import statement should appear before any class definitions in a source file. Multiple import statements are allowed. The following is an example of importing a particular class: import firstPackage.secondPackage.MyClass; After defining this statement, all the members of the class Myclass can be directly accessed using name or its objects (as the case may be) directly without using the package name. We can also use another approach as follows: import packagename.*; Here, packagename may denote a single package or a hierarchy of packages as mentioned earlier. The star (*) indicates that the compiler should search this entire package hierarchy when it encounters a class name. This implies that we can access all classes contained in the above package directly. The major drawback of the shortcut approach is that it is difficult to determine from which package a particular member came. This is particularly true when a large number of packages are imported. But the advantage is that we need not have to use long package names repeatedly in the program. USING A PACKAGE Let us now consider some simple programs that will use classes from other packages. The listing below shows a package named package 1 containing a single class ClassA. package package1; public class ClassA { public void displayA( ) { System.out.println(â&#x20AC;&#x153;Class Aâ&#x20AC;?); } } This source file should be named ClassA.java and stored in the subdirectory package1 as stated earlier. Now compile this java file. The resultant ClassA.class will be stored in the same directory. Now consider the listing shown below: import package1.ClassA; class PackageTest1 { public static void main(String args[ ]) { ClassA objectA = new ClassA( ); objectA.displayA( ); } } This listing shows a simple program that imports the class ClassA from the package package1. The source file should be saved as PackageTest1.java and then compiled. The source file and the compiled file would be saved in the directory of which package1 was a subdirectory. Now we can run the program and obtain the results. During the compilation of packageTest1.java the compiler checks for the file ClassA.class in the package1 directory for information it needs, but i does not actually include the code from ClassA.class in the file PackageTest1.class. When the PackageTest1 program is run, Java looks
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
139
for the file PackageTest1.class and loads it using something called class loader. Now the interpreter knows that it also needs the code in the file ClassA.class and loads it as well. Now let us consider another package named package2 containing again a single class as shown below: package package2; public class ClassB { protected in m = 10 public void displayB ( ) { System.out.println(“Class B”); System.out.println(“m = “ + m); } } As usual, the source file and the compiled file of this package are located in the subdirectory package2.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
140
UNTI V MULTITHREADED PROGRAMMING Those who are familiar with the modern operating systems such as Windows 95 may recognize that they can execute several programs simultaneously. This ability is known as multitasking. In system’s terminology, it is called multithreading. Multithreading is a conceptual programming paradigm where a program (process) is divided into two or more subprograms (process), which can be implemented at the same time in parallel. For example, one subprogram can display an animation on the screen while another may build the next animation to be displayed. This is something similar to dividing a task into subtasks and assigning them to different people for execution independently and simultaneously. In most of our computers, we have only a single processor and therefore, in reality, the processor is doing only one thing at a time. However, the processor switches between the processes so fast that it appears to human beings that all of them are being done simultaneously. Java programs that we have seen and discussed so far contain only a single sequential flow of control. This is what happens when we execute a normal program. The program begins, runs through a sequence of executions, and finally ends. At any given point of time, there is only one statement under execution. A thread is similar to a program that has a single flow of control. It has a beginning, a body, and an end, and executes commands sequentially. In fact, all main programs in our earlier examples can be called single-threaded programs. Every program will have at least one thread as shown in Fig. 12.1. A unique property of Java is its support for multithreading. That is, Java enables us to use multiple flows of control in developing programs. Each flow of control may be thought of as a separate tiny program (or module) known as a thread that runs in parallel to others as shown in Fig.12.2. A program that contains multiple flows of control is known as multithreaded program. Figure illustrates a Java program with four threads, one main and three others. The main thread is actually the main method module, which is designed to create and start the other three threads, namely A, B and C.
class ABC { ........... ........... ...........
Beginning Single-threaded body of execution
........... ........... ........... ........... End ........... Once initiated by the main thread, the threads A, B, and C run concurrently and share the three threads, namely A, B and C. ...........
Once initiated by the main thread, the threads A, B and C run concurrently and share the resources jointly. It is like people living in joint families and sharing certain resources among all of } them. The ability of a language to support multithreads is referred to as concurrency. Since threads in Java are subprograms of a main application program and share the same memory space, they are known as lightweight threads or lightweight processes. It is important to remember that ‘threads running in parallel’ does not really mean that they actually run at the same time. Since all the threads are running on a single processor, the flow of execution is shared between the threads. The Java interpreter handles the switching of control between the threads in such a way that it appears they are running concurrently. Multithreading is a powerful programming tool that makes Java distinctly different from its fellow programming languages. Multithreading is useful in a number of ways. It enables
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
141
programmers to do multiple things at one time. They can divide a long program (containing operations that are conceptually concurrent) into threads and execute them in parallel. For example, we can send tasks such as printing into the background and continue to perform some other task in the foreground. This approach would considerably improve the speed of our programs. Threads are extensively used in Java-enabled browsers such as HotJava. These browsers can download a file to the local computer, display a Web page in the window, output another Web page to a printer and so on. Any application we are working on that requires two or more things to be done at the same time is probably a best one for use of threads. CREATING THREADS Creating threads in Java is simple. Threads are implemented in the form of objects that contain a method called run( ). The run( ) method is the heart and soul of any thread. It makes up the entire body of a thread and is the only method in which the threadâ&#x20AC;&#x2122;s behaviour can be implemented. A typical run( ) would appear as follows:
public void run ( ) { ............ ............ (statements for implementing thread) ............ } The run( ) method should be invoked by an object of the concerned thread. This can be achieved by creating the thread and initiating it with the help of another thread method called start( ). A new thread Can be created in two ways. 1. By creating a thread class: Define a class that extents Thread class and override its run( ) method with the code required by the thread. 2. By converting a class to a thread: Define a class that implements Runnable interface. The Runnable interface has only one method, run( ), that is to be defined in the method with the code to be executed by the thread. The approach to be used depends on what the class we are creating requires. If it requires to extend another class, then we have no choice but to implement the Runnable interface, since java classes cannot have two superclasses. EXTENDING THE THREAD CLASS We can make our class runnable as a thread by extending the class java.lang.Thread. This gives us access to all the thread method directly. It includes the following steps: 1. Declare the class as extending the Thread class. 2. Implement the run( ) method that is responsible for executing the sequence of code that the thread will execute. 3. Create a thread object and call start( ) method to initiate the thread execution. Declaring the Class The Thread class can be extended as follows: class MyThread extends Thread { .......... .......... .......... } Now we have a new type of thread MyThread. Implementing the run( ) Method The run( ) method has been inherited by the class MyThread. We have to override this method in order to implement the code to be executed by our thread. The basic implementation of run( ) will look like this:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
142
public void run( ) { ......... ......... // Thread code here ......... } When we start the new thread, Java calls the threadâ&#x20AC;&#x2122;s run( ) method, so it is the run( ) where all the action takes place. Starting New Thread To actually create and run an instance of our thread class, we must write the following: MyThread aThread = new MyThread( ); aThread.start( ); //invokes run( ) method The first line instantiates a new object of class MyThread. Note that this statement just creates the object. The thread that will run this object is not yet running. The thread is in a newborn state. The second line calls the start( ) method causing the thread to move into the runnable state. Then, the Java runtime will schedule the thread to run by invoking its run( ) method. Now, the thread is said to be n the running state. STOPPING AND BLOCKING A THREAD Stopping a Thread Whenever we want to stop a thread from running further, we may do so by calling its stop( ) method, like: aThread.stop( ); This statement causes the thread to move to the dead state. A thread will also move to the dead state automatically when it reaches the end of its method. The stop( ) method may be used when the premature death of a thread is desired. Blocking a Thread A thread can also be temporarily suspended or blocked from entering into the runnable and subsequently running state by using either of the following thread methods: sleep( ) // blocked for a specified time suspend( ) // blocked until further orders wait( ) // blocked until certain condition occurs These methods cause the thread to go into the blocked (or not-runnable) state. The thread will return to the runnable state when the specified time is elapsed in the case of sleep( ), the resume( ) method is invoked in the case of suspend( ), and the notify( ) method is called in the case of wait( ). LIFE CYCLE OF A THREAD During the life time of a thread, there are many states it can enter. They include: 1. Newborn state 2. Runnable state 3. Running state 4. Blocked state 5. Dead state A thread is always in one of these five states. It can move from one state to another via a variety of ways as shown in Fig..
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
New Thread
143
Newbor n stop
start
stop Active Thread
Running
Running
Dea d
yield
suspend sleep wait
Idle Thread (Not Runnable)
Killed Threa d
stop
resume notify
Blocked
Newborn State When we create a thread object, the thread is born and is said to be in newborn state. The thread is not yet scheduled for running. At this state, we can do only one of the following things with it: Schedule it for running using start( ) method. Kill it using stop( ) method. If scheduled, it moves to the runnable state (fig.). if we attempt to use any other method at this stage, an exception will be thrown.
Newbor n
Runnabl e state
Dead state
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
144
Runnable State The runnable state means that the thread is ready for execution and is waiting for the availability of the processor. That is, the thread has joined the queue of threads that are waiting for execution. If all threads have equal priority, then they are given time slots for execution in round robin fashion, i.e., first-come, first-serve manner. The thread that relinquishes control joins the queue at the end and again waits for its turn. This process of assigning time to threads is known as time-slicing. However, if we want a thread to relinquish control to another thread of equal priority before its turn comes, we can do so by using the yield( ) method (Fig.). yield
Runnin g RunningThread State
Runnable Threads
Running means that the processor has given its time to the thread for its execution. The thread runs until it relinquishes control on its own or it is preempted by a higher priority thread. A running thread may relinquish its control in one of the following situations. 1. It has been suspended using suspend( ) method. A suspended thread can be revived by using the resume( ) method. This approach is useful when we want to suspend a thread for some time due to certain reason, but do not want to kill it.
Suspend
resume
Relinquishing control using suspend( ) method Running Runnable Suspende 2. It has been made to sleep. We can put a thread to sleep for a specified time period using the d is out of the method sleep(time) where time is in milliseconds. This means that the thread queue during this time period. The thread re-enters the runnable state as soon as this time period is elapsed.
sleep(t)
after t
Running
Relinquishing control using sleep( ) method
Runnable
Sleeping
3. It has been told to wait until some event occurs. This is done using the the wait( ) method. The thread can be scheduled to run again using the notify( ) method.
wait
notify
Running
Waiting
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
145
Relinquishing control using wait( ) method Blocked State A thread is said to be blocked when it is prevented from entering into the runnable state and subsequently the running state. The happens when the thread is suspended, sleeping, or waiting in order to satisfy certain requirements. A blocked thread is considered “not runnable” but not dead and therefore fully qualified to run again. Dead State Every thread has a life cycle. A running thread ends its life when it has completed executing its run( ) method. It is a natural death. However, we can kill it by sending the stop message to it at any state thus causing a premature death to it. A thread can be killed as soon it is born, or while it is running, or even when it is in “not runnable” (blocked) condition. USING THREAD METHODS We have discussed how Thread class methods can be used to control the behaviour of a thread. We have used the methods start( ) and run( ),yield( ), sleep( ) and stop( ) methods in example program. THREAD EXCEPTIONS Note that the call to sleep( ) method is enclosed in a try block and followed by a catch block. This is necessary because the sleep( ) method throws an exception, which should be caught. If we fail to catch the exception, program will not compile. Java run system will throw IllegalThreadStateException whenever we attempt to invoke a method that a thread cannot handle in the given state. For example, a sleeping thread cannot deal with the resume( ) method because a sleeping thread cannot receive any instructions. The same is true with the suspend( ) method when it is used on a blocked (Not Runnable) thread. Whenever we call a thread method that is likely to throw an exception, we have to supply an appropriate exception handler to catch it. The catch statement may take one of the following forms: catch (ThreadDeath e) { ........... ........... // Killed thread } catch (InterruptedException e) { ........... ........... // Cannot handle it in the current state } catch (Illegal1Argument Exception e) { ........... ........... // Illegal method argument } catch (Exception e) { ........... ........... // Any other } Exception handling is discussed in detail in Chapter 13.
THREAD PRIORITY In Java, each thread is assigned a priority, which affects the order in which it is scheduled for running. The threads that we have discussed so far are of the same priority. The threads of the same priority are given equal treatment by the Java scheduler and, therefore, they share the processor on a firstcome, first-serve basis.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
146
Java permits us to set the priority of a thread using the setPriority( ) method as follows:
ThreadName.setPriority(intNumber); The intNumber is an integer value to which the thread’s priority is set. The Thread class defines several priority constants: MIN_PRIORITY = 1 NORM_PRIORITY MAX_PRIORITY
=5 = 10
The intNumber may assume one of these constant or any value between 1 and 10. Note that the default setting is NORM_PRIORITY. Most user-level processes should use NORM_PRIORITY, plus or minus 1. Back-ground tasks such as network I/O and screen repainting should use a value very near to the lower limit. We should be very cautious when trying to use very high priority values. This may defeat the very purpose of using multithreads. By assigning priorities to threads, we can ensure that they are given the attention (or lack of it) they deserve. For example, we may need to answer an input as quickly as possible. Whenever multiple threads are ready for execution, the Java system chooses the highest priority thread and executes it. For a thread of lower priority to gain control, one of the following things should happen: 1. It stops running at the end of run( ). 2. It is made to sleep using sleep( ). 3. It is told to wais using wait( ). However, if another thread of a higher priority comes along, the currently running thread will be preempted by the incoming thread thus forcing the current thread to move to the runnable state. Remember that the highest priority thread always preempts any lower priority threads. SYNCHRONIZATION So far, we have seen threads that use their own data and methods provided inside their run( ) methods. What happens when they try to use data and methods outside themselves? On such occasions, they may compete for the same resources and may lead to serious problems. For example, they may compete for the same resources and may lead to serious problems. For example, one thread may try to read a record from a file while another is still writing to the same file. Depending on the situation, we may get strange results. Java enables us to overcome this problem using a technique known as synchronization. In case of Java, the keyword synchronised helps to solve such problem by keepings a watch on such locations. For example, the method that will read information from a file and the method that will update the same file may be declared as synchronized. Example:
synchronized void update ( ) { ........... ........... // code here is synchronized ........... } When we declare a method synchronized, Java creates a “monitor” and hands it over to the thread that calls the method first time. As long as the thread holds the monitor, no other thread can
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
147
enter the synchronized section of code. A monitor is like a key and the thread that holds the key can only open the lock. It is also possible to mark a block of code as synchronized as shown below: synchronized (lock-object) { .......... // code here is synchronized .......... } Whenever a thread has completed its work of using synchronized method (or block of code), it will hand over the monitor to the next thread that is ready to use the same resource. An interesting situation may occur when two or more threads are waiting to gain control of a resource. Due to some reason, the condition on which the waiting threads rely on to gain control does not happen. This results in what is known as deadlock. For example, assume that the thread A must access Method 1 before it can release Method2, but the thread B cannot release Method1 until it gets hold of Method2. Because these are mutually exclusive conditions, a deadlock occurs. The code below illustrates this: Thread A synchronized method2 ( ) { synchronized method1 ( ) { .......... .......... } } Thread B synchronized method1 ( ) { synchronized method2 ( ) { .......... .......... } } IMPLEMENTING THE ‘RUNNABLE’ INTERFACE We stated earlier that we can create threads in two ways: one by using the extended Thread class and another by implementing the Runnable interface. We have already discussed in detail how the Thread class is used for creating and running threads. In this section, we shall see how to make use of the Runnable interface to implement threads. The Runnable interface declares the run( ) method that is required for implementing threads in our programs. To do this, we must perform the steps listed below: 1. Declare the class as implementing the Runnable interface. 2. Implement the run( ) method. 3. Create a thread by defining an object that is instantiated from this “runnable” class as the target of the thread. 4. Call the thread’s start( ) method to run the thread. Program 12.4 illustrates the implementation of the above steps. In main method, we first create an instance of X and then pass this instance as the initial value of the object threadX (an object
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
148
of Thread Class). Whenever, the new thread threadX starts up, its run( ) method calls the run( ) method of the target object supplied to it. Here, the target object is runnable. If the direct reference to the thread threadX is not required, then we may use a shortcut as shown below: new Thread (new x( )).start( ); Program 12.4 Using Runnable interface class X implements Runnable //Step 1 { //Step 2 public void run( ) { for(int i = 1; i<=10; i++) { System.out.println(“tThreadX : “+i); } System.out.println(“End of ThreadX”); } } class RunnableTest { public static void main(String args[ ]) { X runnable = new X( ); Thread threadX = new Thread(runnable);//Step 3 threadx.start( ); // Step 4 system.out.println(“End of main Thread:); } }
MANAGING ERRORS AND EXCEPTIONS Rarely does a program run successfully at its very first attempt. It is common to make mistakes while developing as well as typing a program. A mistake might lead to an error causing the program to produce unexpected results. Errors are the wrongs that can make a program go wrong. An error may produce an incorrect output or may terminate the execution of the program abruptly or even may cause the system to crash. It is therefore important to detect and manage properly all the possibly error conditions in the program so that the program will not terminate or crash execution. TYPES OF ERRORS Errors may broadly be classified into two categories: Compile-time errors Run-time errors Compile-Time Errors All syntax errors will be detected and displayed by the Java compiler and therefore these errors are known as compile-time errors. Whenever the compiler displays an error, it will not create the .class file. It is therefore necessary that we fix all the errors before we can successfully compile and run the program. Program 13.1 Illustration of compile-time errors /* This program contains an error */ class Error1
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
149
{ public static void main(String args[ ]) { System.out.println(“Hello Java!”) }
// Missing;
}
The Java compiler does a nice job of telling us where the errors are in the program. For example, if we have missed the semicolon at the end of print statement in Program 13.1, the following message will be displayed in the screen:
Error1.java :7: ‘;’ expected System.out.println (“Hello Java!”) ^ 1 error We can now go to the appropriate line, correct the error, and recompile the program. Sometimes, a single error may be the source of multiple errors later in the compilation. For example, use of an undeclared variable in a number of places will cause a series of errors of type “undefined variable”. We should generally consider the earliest errors as the major source of our problem. After we fix such an error, we should recompile the program and look for other errors. Most of the compile-time errors are due to typing mistakes. Typographical errors are hard to find. We may have to check the code word by word, or even character by character. The most common problems are:
Missing semicolons Missing (or mismatch of) brackets in classes and methods Misspelling of identifiers and keywords Missing double quotes in strings Use of undeclared variables Incompatible types in assignments/initialization Bad references to objects Use of = in place of = = operator And so on
Other errors we may encounter are related to directory paths. An error such as java : command not found means that we have not set the path correctly. We must ensure that the path includes the directory where the Java executables are stored. Run-Time Errors Sometimes, a program may compile successfully creating the .class file but may not run properly. Such programs may produce wrong results due to wrong logic or may terminate due to errors such as stack overflow. Most command run-time errors are:
Dividing an integer by zero Accessing an element that is out of the bounds of an array. Trying to store a value into an array of an incompatible class or type. Trying to cast an instance of a class to one of its subclasses. Passing a parameter that is not in a valid range or value for a method. Trying to illegally change the state of a thread. Attempting to use a negative size for an array.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
150
Using a null object reference as a legitimate object reference to access a method or a variable. Converting invalid string to a number. Accessing a character that is out of bounds of a string. And many more
When such errors are encountered, Java typically generates an error message and aborts the program. Program 13.2 illustrates how a run-time error causes termination of execution of the program. Program 13.2 Illustration of run-time errors class Error2 { public static void main(String args[ ]) { int a = 10; int b = 5; int c = 5; int x = a/(b-c); //Division by zero System.out.println(“x = “ + x); int y = a/(b+c); System.out.println(“y = “ + y); { } Program 13.2 is syntactically correct and therefore does not cause any problem during compilation. However, while executing, it displays the following message and stops without executing further statements. java.lang.ArithmeticException: / by zero at Error2.main(Error2.java:10) When Java run-time tries to execute a division by zero, it generates an error condition, which causes the program to stop after displaying an appropriate message. EXCEPTIONS An exception is a condition that is caused by a run-time error in the program. When the Java interpreter encounters an error such as dividing an integer by zero, it creates an exception object and throws it( (i.e., informs us that an error has occurred). If the exception object is not caught and handled property, the interpreter will display an error message as shown in the output of Program 13.2 and will terminate the program. If we want the program to continue with the execution of the remaining code, then we should try to catch the exception object thrown by the error condition and then display an appropriate message for taking corrective actions. This task is known as exception handling. The purpose of exception handling mechanism is to provide a means to detect and report an “exceptional circumstance” so that appropriate action can be taken. The mechanism suggests incorporation of a separate error handling code that performs the following tasks: 1. 2. 3. 4.
Find the problem (Hit the exception). Inform that an error has occurred (Throw the exception) Receive the error information (Catch the exception) Take corrective actions (Handle the exception)
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
151
The error handling code basically consists of two segments, one to detect errors and to throw exceptions and the other to catch exceptions and to take appropriate actions. When writing programs, we must always be on the lookout for places in the program where an exception could be generated, Some common exception that we must watch out for catching are listed in Table 13.1. Exception Type
Cause of Exception
Arithmetic Exception
Caused by math errors such as division by zero
ArrayIndexOutofBoundsException
Caused by bad array indexes
ArrayStoreException
Caused when a program tries to store the wrong type of data in an array
FileNotFoundException
Caused by an attempt to access a nonexistent file
Table 13.1 (Continued) Exception Type
Cause of Exception
IOException
Caused by general I/O failures, such as iniability to read from a file
NullPointerException
Caused by referencing a null object
NumberFormatException
Caused when a conversion between strings and number falls
OutOfMemoryException
Caused when there’s not enough memory to allocate a new object
SecurityException
Caused when an applet tries to perform an action not allowed by the browser’s security setting
StackOverflowException
Caused when the system runs out of stack space
StringIndexOutOFBoundsException
Caused when a program attempts to access a nonexistent character position in a string
SYNTAX OF EXCEPTION HANDLING CODE The basic concepts of exception handling are throwing an exception and catching it. This is illustrated in Fig. 13.1.
try Block
Throws exceptio n object
Statement that causes an exception
Exception object creator
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
152
try Block Statement that causes an exception
Exception handler
Exception handling mechanism Java uses a keyword try to preface a block of code that is likely to cause an error condition and “throw” an exception. A catch block defined by the keyword catch “catches” the exception “thrown” by the try block and handles it appropriately. The catch block is added immediately after the try block. The following example illustrates the use of simple try and catch statements. ............ ............ try { statement; //generates an exception } catch (Exception type e) { statement; //processes the exception } .......... .......... The try block can have one or more statements that could generate an exception. If any one statement generates an exception, the remaining statements in the block are skipped and execution jumps to the catch block that is placed next to the try block. The catch block too can have one or more statements that are necessary to process the exception. Remember that every try statement should be followed by at least one catch statement; otherwise compilation error will occur. Note that the catch statement works like a method definition. The catch statement is passed a single parameter, which is reference to the exception object thrown (by the try block). If the catch parameter matches with the type of exception object, then the exception is caught and statements in the catch block will be executed. Otherwise, the exception is not caught and the default exception handler will cause the execution to terminate. Program 13.3. illustrates the use of try and catch blocks to handle an arithmetic exception. Note the Program 13.3. is a modified version of Program 13.2. Program 13.3 Using try and catch for exception handling class Error3 { public static void main(String args[ ]) { int a = 10; int b = 5; int c = 5; int x, y ; try { x = a / (b-c); } catch (ArithmeticException e) {
// Exception here
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
153
System.out.println(“Division by zero”); } y = a / (b+c); System.out.println(“y = “ + y); } } Program 13.3. displays the following output: Division by zero y=1 Note that the program did not stop at the point of exception condition. It catches the error condition, prints the error message, and then continues the execution, as if nothing has happened. Compare with the output of Program 13.2 which did not give the value of y. Program 13.4. shows another example of using exception handling mechanism. Here, the try-catch block catches the invalid entries in the list of command line arguments.. Program 13.4 Catching invalid command line arguments class CLineInput { public static void main(String args[ ]) { int invalid = 0; //Number of invalid arguments int number, count = 0; for (int i = 0; i <args.length, i++) { try { number = Integer.parseInt(args[i]); } catch (NumberFormatException e) { invalid = invalid +1; //Caught an invalid number System.out.println(“Invalid Number: “+args[i]) Continue; //Skip the remaining part of the loop } count = count + 1; } System.out.println(“valid Numbers=”+ count); System.out.println(“Invalid Numbers = “+invalid); } } Note the use of the wrapper class Integer to obtain an int number from a string: number = integer.parseInt(args[i]) Remember that the numbers are supplied to the program through the command line and therefore they are stored as strings in the array args [ ]. Since the above statement is placed in the try block, an exception is thrown if the string is improperly formatted and the number is not included in the count. When we run the program with the command line: java CLineInput 15 25.75 40 Java 10.5 65 it produces the following output:
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
154
Invalid number : 25.75 Invalid number : Java Invalid number : 10.5 Valid numbers = 3 Invalid number = 3
MULTIPLE CATCH STATEMENTS It is possible to have more than one catch statement in the catch block as illustrated below: ............ ............ try { statement; } catch (Exception-Type-1 e) { statement; } catch (Exception-Type-2 3) statement; } . . . catch (Exception-Type-N 3) statement; } ........... ...........
//generates an exception
//processes exception type 1
//processes exception type 2
//processes exception type N
When an exception in a try block is generated, the Java treats the multiple catch statements like cases in a switch statement. The first statement whose parameter matches with the exception object will be executed, and remaining statements will skipped. Note that Java does not require any processing of the exception at all. We can simply have a catch statement with an empty block to avoid program abortion. Example: catch (Exception e); The catch statement simply ends with a semicolon, which does nothing. This statement will catch an exception and then ignore it. Program 13.5. Using multiple catch block class Error4 { public static void main(String args[ ]) { int a[ ] = {5,10}; int b = 5; try {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
155
int x = a[2] / b – a[1]; } catch(Arithmetic Exception e) { System.out.println(“Division by zero”); } catch(ArrayIndexOutofBoundsException e) { System.out.println(“Array index error”); } int y = a[1] / a[0]; System.out.println(“y = “ + y); } } Program 13.5 uses a chain of catch blocks and, when run, produces the following output: Array index error y=2 Note that the array element a[2] does not exist because array a is defined to have only two elements, a[0] and a[1]. Therefore, the index 2 is outside the array boundary thus causing the block. Catch(ArrayIndexOutOfBoundsException e) to catch and handle the error. Remaining catch blocks are skipped. USING finally STATEMENT Java supports another statement known as finally statement that can be used to handle an exception that is not caught by any of the previous catch statements. finally block can be used to handle any exception generated within a try block. It may be added immediately after the try block or after the last catch block shown as follows:
try { ......... ......... } finally { ......... ......... } try { ......... ......... } catch (....) { ......... ......... } catch (....) { .........
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
156
......... } . . . . finally { ......... ......... } When a finally block is defined, this is guaranteed to execute, regardless of whether or not an exception is thrown. As a result, we can use it to perform certain house-keeping operations such as closing files and releasing system resources. In program 13.5, we may include the last two statements inside a finally block as shown below: finally { int y = a[1]/a[0]; System.out.println(“y = “+y)’ } This will produce the same output. THROWING OUR OWN EXCEPTIONS There may be items when we would like to throw our own exceptions. We can do this by using the keyword throw as follows:
throw new Throwable_subclass; Examples: throw new ArithmeticException( ); throw new NumberFormatException( ); Program 13.6 demonstrates the use of user-defined subclass of Throwable class. Note that Exception is a subclass of Throwable and therefore MyException is a subclass ofThrowable class. An object of a class that extent Throwable can be thrown and caught. Program 13.6 Throwing out own exception import java.lang.Exception; class MyException(String message) { MyException(String message) { super(message); } } class TestMyException { public static void main(String args[ ]) { int x = 5, y = 1000; try {
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
157
float z = (float) x / (float) y ; if (x <0.01) { throw new MyException(“Number is too small”); } } catch (MyException e) { System.out.println(“Caught my exception”); System.out.println(e.getMessage( )); } finally { System.out.println(“I am always here”); } } } A run of program 13.6 produces: Caught my exception Number is too small I am always here The object e which contains the error message “Number is too small” is caught by the catch block which then displays the message using the getMessage( ) method. Note that Program 13.6 also illustrates the use of finally block. The last line of output is produced by the finally block. USING EXCEPTIONS FOR DEBUGGING As we have seen, the exception-handling mechanism can be used to hide errors from rest of the program. it is possible that the programmers may misuse this technique for hiding errors rather than debugging the code. Exception handling mechanism may be effectively used to locate the type and place of errors. Once we identify the errors, we must try to find out why these errors occur before we cover them up with exception handlers. Chapter 14 APPLET PROGRAMMING INTRODUCTION Applets are small Java programs that are primarily used in Internet computing. They can be transported over the Internet from one computer to another and run using the Applet Viewer or any Web browser that supports java. An applet, like any application program, can do many things for us. It can perform arithmetic operations, display graphics, play sounds, accept user input, create animation, and play interactive games. Java was revolutionized the way the Internet users retrieve and use documents on the world wide network. Java has enabled them to create and use fully interactive multimedia Web documents. A web page can now contain not only a simple text or a static image but also a Java applet which, when run, can produce graphics, sounds and moving images. Java applets therefore have begun to make a significant impact on the World Wide Web.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
158
APPLET LIFE CYCLE Every Java applet inherits a set of default behaviours from the Applet class. As a result, when an applet is loaded, it undergoes a series of changes in its state as shown in Fig. 14.5. The applet states include:
Born or initialization state Running state Idle state Dead or destroyed state
Begin (Load Applet)
Born
start( )
stop( )
Running
Display
Initializatio n
start( )
Stopped
Idle
paint( )
destroy ( )
Destroyed
Dead
End
Exit of Browser Initialization State Applet enters the initialisation state when it is first loaded. This is achieved by calling the init( ) method of Applet Class. The applet is born. At this stage, we may do the following, if required.
Create objects needed by the applet Set up initial values Load images of fonts Set up colors
The initialization occurs only once in the applet’s life cycle. To provide any of the behaviours mentioned above, we must override the init( ) method: public void init ( ) { ......... ......... (Action) ......... }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
159
Running State Applet enters the running state when the system calls the start( ) method of Applet Class. This occurs automatically after the applet is initialized. Starting can also occur if the applet is already in “stopped” (idly) state. For example, we may leave the Web page containing the applet temporarily to another page and return back to the page. This again starts the applet running Note that, unlike int( ) method, the start ( ) method may be called more than once. We may ovrride the start( ) method to create a thread to control the applet. public void start( ) { ......... ......... (Action) ......... } Idle or Stopped State An applet becomes idle when it is stopped from running. Stopping occurs automatically when we leave the page containing the currently running applet. We can also do so by calling the stop( ) method explicitly. If we use a thread to run the applet, then we must use stop ( ) method to terminate the thread. We can achieve this by overriding the stop( ) method. public void stop( ) { ............ ............ (Action) ............ }
Dead State An applet is said to be dead when it is removed from memory. This occurs automatically by invoking the destroy ( ) method when we quit the browser. Like initialization, destroying stage occurs only once in the applet’s life cycle. If the applet has created any resources, like threads, we may override the destroy ( ) method to clean up these resources. public void destroy ( ) { ........... ........... (Action) ........... } Display State Applet moves to the display state whenever it has to perform some output operations on the screen. This happens immediately after the applet enters into the running state. The paint ( ) method is called to accomplish this task. Almost every applet will have a paint ( ) method. Like other methods in the life cycle, the default version of paint ( ) method does absolutely nothing. We must therefore override this method if we want anything to be displayed on the screen. public void paint (graphics g) { ......... ......... (Display statements) ......... }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
160
It is to be noted that the display state is not considered as a part of the appletâ&#x20AC;&#x2122;s life cycle. In fact, the paint( ) method is not defined in the Applet class. It is inherited from the Component class, a super class of Applet. CREATING AN EXECUTABLE APPLET Executable applet is nothing but the .class file of the applet, which is obtained by compiling the source code of the applet. Compiling an applet is exactly the same as compiling an application. Therefore, we can use the Java compiler the applet. Let us consider the HelloJava applet created in Section 14.4. This applet has been stored in a file called HelloJava.java. Here are the steps required for compiling the Hellojava applet. 1. Move to the directory containing the source code and type the following command: javac HelloJava.java 2. The compiled output file called HelloJava.class is placed in the same directory as the source. 3. If any error message is received, then we must check for errors, correct them and compile the applet again. APPLET TAG Note that we have included a pair of <APPLET....> and </APPLET> tags in the body section discussed above. The <APPLET ...> tag supplies the name of the applet to be loaded and tells the browser how much space the applet requires. The ellipsis in the tag <APPLET ...> indicates that it contains certain attributes that must specified. The <APPLET> tag given below specifies the minimum requirements to place the JellowJava applet on a Web page: <APPLET CODE = helloJava.class WIDTH = 400 HEIGHT = 200> </APPLET > This HTML code tells the browser to load the compiled Java applet HelloJava.class, which is in the same directory as this HTML file. And also specifies the display area for the applet output as 400 pixels width and 200 pixels height. We can make this display area appear in the centre of the screen by using the CENTRE tags as shown below: <CENTER> <APPLET ......... ......... ......... </APPLET> </CENTER> Note that <APPLET> tag discussed above specifies three things: 1. Name of the applet 2. Width of the applet (in pixels) 3. Height of the applet (in pixels)
ADDING APPLET TO HTML FILE Now we can put together the various components of the Web page and create a file known as HTML file. Insert the <APPLET> tag in the page at the place where the output of the applet must appear. Following is the content of the HTML file that is embedded with the <APPLET> tag of our HelloJava applet. <HTML>
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
161
<! This page include a welcome title in the title bar and also displays a welcome message. Then it specifies the applet to be loaded and executed. > <HEAD> <TITLE> Welcome to Java Applets <TITLE> </HEAD> <BODY> <CENTER> <H1> welcome to the world of Applets</H1> </CENTER> <BR> <CENTER> <APPLET> CODE = HelloJava.class WIDTH = 400 HEIGHT = 200> </APPLET> </CENTER> </BODY> </HTML> RUNNING THE APPLET Now that we have created applet files as well as the HTML file containing the applet, we must have the following files in our current directory: HelloJava.java HelloJava.class HelloJava.html To run an applet, we require one of the following tools: 1. Java-enabled Web browser (such as HotJava or Netscape) 2. Java appletviewer If we use a Java-enabled Web browser, we will be able to see the entire Web page containing the applet. If we use the appletviewer tool, we will only see the applet output. Remember that the appletviewer is not a full-fledged Web browser and therefore it ignores all of the HTML tags except the part pertaining to the running of the applet The appletviewer is available as a part of the Java Development Kit that we have been using so far. We can use it to run our applet as follows: appletviewer HelloJava.html Notice that the argument of the appletviewer is not the java file or the .class file, but rather .html file. The output of our applet will be as shown in Fig. 14.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
162
Applet Viewer : HelloJava.class
Applet
Hello Java
apletloader.started DISPLAYING NUMERICAL VALUES In applets, we can display numerical values by first converting them into strings and then using the drawString( ) method of Graphics class. We can do this easily by calling the ValueOf( ) method of String class. Program 14.5 illustrates how an applet handles numerical values. Program 14.5 Displaying numerical values
import java.awt.*; import java.applet.*; public class Numvalues extends Applet { public void paint(Graphics g) { int value1 = 10; int value2 = 20; int sum = value1 + value2: string s = â&#x20AC;&#x153;sum: â&#x20AC;&#x153;+ string.valueOf(sum); g.drawString(s, 100, 100); } }
GETTING INPUT FROM THE USER Applets work in a graphical environment. Therefore, applets treat inputs as text strings. We must first create an area of the screen in which user can type and edit input items (which may be any data type). We can do this by using the TextField class of the applet package. Once text fields are created for receiving input, we can type the values in the fields and edit them, if necessary. Next steps is to retrieve the items from the fields for display of calculations, if any. Remember, the text fields contain items in string form. They need to be converted to the right form, before they are used in any computations. The results are then converted back to strings for display.
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
163
Chapter 15 GRAPHICS PROGRAMMING
THE GRAPHICS CLASS Javaâ&#x20AC;&#x2122;s Graphics class includes methods for drawing many different types of shapes, from simple lines to polygons to text in a variety of fonts. We have already seen how to display text using the paint( ) method and a Graphics object. To draw a shape on the screen, we may call one of the methods available in the Graphics class. Table 15.1 shows the most commonly used drawing methods in the Graphics class. All the drawing methods have arguments representing end points, corners, or starting locations of a shape as values in the appletâ&#x20AC;&#x2122;s coordinate system. To draw a shape, we only need to use the appropriate method with the required arguments.
Table 15.1 Drawing Methods of the Graphics Class Method clearrect( ) copyArea( ) drawArc( ) drawLine( ) drawOval( ) drawPolygon( ) drawRect( ) drawRoundRect( ) drawString( ) fillArc( ) fillOval( ) fillpolygon( ) fillRect( ) fillRoundRect( ) getColor( ) getFont( ) getFontMetrics( ) setColor( ) setFong( )
Description Erases a rectangular area of the canvas. Copies a rectangular area of the canvas to another area. Draws a hollow arc. Draws a straight line. Draws a hollow oval. Draws a hollow polygon. Draws a hollow rectangle. Draws a hollow rectangle with rounded corners. Displays a text string. Draws a filled arc. Draws a filled oval. Draws a filled polygon. Draws a filled rectangle. Draws a filled rectangle with rounded corners. Retrieves the current drawing colour. Retrieves the currently used font. Retrieves information about the current font. Sets the drawing colour. Sets the font.
LINES AND RECTANGLES The simplest shape we can draw with the Graphics class is a line. The drawLine( ) method takes two pair of coordinates, (x1, y1) and (x2, y2) as arguments and draws a line between them. For example, the following statement draws a straight line from the coordinate point (10,10) to (50,50): g.drawLine(10,10, 50,50); The g is the Graphics object passed to paing( ) method. Similarly, we can draw a rectangle using the drawRect( ) method. This method takes four arguments. The first two represent the x and y coordinates of the top left corner of the rectangle, and the remaining two represent the width and the height of the rectangle. For example, the statement
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
g.drawrect(10, 60,
164
40, 30);
(x, y)
width
height
Rectangle will draw a rectangle starting at (10,60) having a width of 40 pixels and a height of 30 pixels, Remember that the drawRect( ) method draws only the outline of a box. We can draw a solid box by using the method fillRect( ). This also takes four parameters (as drawRect) corresponding to the starting point, the width and the height of the rectangle. For example, the statement g.fillRect(60, 10, 30, 80); will draw a solid rectangle starting at (60,10) with a width of 30 pixels and a height of 80 pixels. We can also draw rounded rectangles (which are rectangles with rounded edges), using the methods drawRoundRect( ) and fillRoundRect( ). These two methods are similar to drawRect( ) and fillRect( ) except that they take two extra arguments representing the width and height of the angle of corners. These extra parameters indicate how much of corners will be rounded. Example: g.drawRoundRect(10,100,80,50,10,10); f.fillRoundRect(20,110,60,30,5,5) Program 15.1 is an applet code that draws three lines, a rectangle, a filled rectangle, a rounded rectangle and filled rounded rectangle. Note that the filled rounded one is drawn inside the rounded rectangle. CIRCLES AND ELLIPSES The Graphics class does not have any method for circles or ellipses. However, the drawOval( ) method can be used to draw a circle or an ellipse. Ovals are just like rectangles with overly rounded corners as shown in Fig.15.3. Note that the figure is surrounded by a rectangle that just touches the edges. The drawOval( ) method takes four arguments: the first two represent the top left corner of the imaginary rectangle and the other two represent the width the height of the oval itself. Note that if the width and height are the same, the oval becomes a circle. The ovalâ&#x20AC;&#x2122;s coordinates are actually the coordinates of an enclosing rectangle. Like rectangle methods, the drawoval( ) method draws outline of an oval, and the fillOval( ) method draws a solid oval. The code segment shown below draws a filled circle within an oval
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
165
height
width
public void paint (Graphics g) { g.drawOval(20,20,200,120); g.setColor(Color.green); g.fillOval(70,30,100,100);
//This is a circle
We can draw an object using a color object as follows: g.setColor(Color.green); After setting the color, all drawing operations will occur in that color. DRAWING ARCS An arc is a part of an oval. In fact, we can think of an oval as a series of arcs that are connected together in an orderly manner. The drawArc( ) designed to draw arcs six arguments. The first four are the same as the arguments for drawOval( ) method and the last two represent the starting angle of the arc and the number of degrees (sweep angle) around the arc. In drawing arcs, Java actually formulates the arc as an oval and then draws only a part of it as dictated by the last two arguments. Java considers the three O’clock position as zero degree position and degrees increase in anti-clockwise direction as shown in Fig.15.5. So, to draw an arc from 12.00 O’ clock position to 6:00 O’clock position, the starting angle would be 90, and the sweep angle would be 180.
90
180 180
0
270
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
166
We can also draw an arc in backward direction by specifying the sweep angle as negative. For example, if the last argument is -135 and the starting angle is 45, then the arc is drawn as shown in Fig.15.6.
45
135
We can use the fillArc( ) method to fill the arc. 270Filled arcs are drawn as if they were sections of a pie. Instead of joining the two end points, they are joined to the centre of the oval. DRAWING POLYGONS Polygons are shapes with many sides. A polygon may be considered a set of lines connected together. The end of the first line is the beginning of the second line, the end of the second is the beginning of the third, and so on. This suggests that we can draw a polygon with n sides using the drawLine( ) method n times in succession. For example, the code given below will draw a polygon of three sides. The output of this code is shown in Fig. 15.8. public void paint(Graphics g) { g.drawLine(10, 20, 170, 40); g.drawLine(170, 40, 80, 140); g.drawLine(80, 140, 10, 20); } Note that the end point of the third line is the same as the starting point of the polygon.
(10, 20) (170, 40)
(80,
We can draw polygons more conveniently using the drawPolygon( ) method of Graphics 140) class. This method takes three arguments:
An array of integers containing x coordinates An array of integers containing y coordinates An integer for the total number of points
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING
167
It is obvious that x and y arrays should be of the same size and we must repeat the first point at the end of the array for closing the polygon. The polygon shown in Fig.15.8 can be drawn using the drawPolygon( ) method as follows: public void paint(Graphics g) { int xPoints[ ] = {10,170,80,10}; int yPoints[ ] = {20,40,140,20}; int nPoints[ ] = xPoints.length; g.drawPolygon (xPoints, yPoints, nPoints); } Example For Applet and Graphics Programming. Example 1 Generating a Face Applet Drawings import java.awt.*; import java.applet.*; /*<APPLET CODE="face.class" WidTH=200 HEIGHT=200></APPLET>*/ public class face extends Applet { public void paint(Graphics g) { g.setColor(Color.green); g.drawOval(40,40,120,150); g.drawOval(57,75,30,20); g.drawOval(110,75,30,20); g.fillOval(68,81,10,10); g.fillOval(121,81,10,10); g.drawOval(85,100,30,30); g.fillArc(60,125,80,40,180,180); g.drawOval(25,92,15,30); g.drawOval(160,92,15,30); } } OUTPUT
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
OBJECT ORIENTED PROGRAMMING 7.2 ARITHMETIC MANIPULATION USING AWT CONTROLS import java.awt.*; import java.applet.*; import java.io.*; import java.awt.event.*; /*<applet code = arith.class height=400 width=700> </applet>*/ public class arith extends Applet implements ActionListener { String s,s1,s2,s3; TextField t1,t2,t3; Label l,l1,l2,l3; Button b1,b2,b3,b4,b5; public void init() { setLayout(null); l =new Label(" ARITHMETIC CALCULATION"); l1 =new Label(" ENTER THE FIRST NUMBER"); l2 =new Label(" ENTER THE SECOND NUMBER"); l3 =new Label(" RESULT"); t1 = new TextField(8); t2 = new TextField(8); t3 = new TextField(8); b1 = new Button("ADDITION"); b2 = new Button("SUBTRACTION"); b3 = new Button("MULTIPLICATION"); b4 = new Button("DIVISION"); b5 = new Button("CLEAR"); l.setBounds(200,10,300,40); l1.setBounds(50,50,160,40); l2.setBounds(50,100,190,40); l3.setBounds(50,150,140,40); t1.setBounds(250,50,100,30); t2.setBounds(250,100,100,30); t3.setBounds(250,150,100,30); b1.setBounds(50,250,100,30); b2.setBounds(200,250,100,30); b3.setBounds(350,250,100,30); b4.setBounds(500,250,100,30); b5.setBounds(650,250,100,30); add(l); add(l1); add(l2); add(l3); add(t1); add(t2); add(t3); add(b1); add(b2); add(b3); add(b4); add(b5); b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); b5.addActionListener(this); }
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
168
OBJECT ORIENTED PROGRAMMING public void actionPerformed(ActionEvent e) { s = e.getActionCommand(); s1=t1.getText(); s2=t2.getText(); Double b = new Double(s1); Double m = new Double(s2); if(s.equals("ADDITION")) s3= Double.toString(b.doubleValue()+m.doubleValue()); if(s.equals("SUBTRACTION")) s3= Double.toString(b.doubleValue()-m.doubleValue()); if(s.equals("MULTIPLICATION")) s3= Double.toString(b.doubleValue()*m.doubleValue()); if(s.equals("DIVISION")) s3= Double.toString(b.doubleValue()/m.doubleValue()); t3.setText(s3); if(s.equals("CLEAR")) { t1.setText(" "); t2.setText(" "); t3.setText(" "); } }}
OUTPUT
FOR MORE DETAILS VISIT US ON WWW.IMTSINSTITUTE.COM OR CALL ON +91-9999554621
169
OBJECTORI ENTED PROGRAMMI NG
Publ i s he dby
I ns t i t ut eofManage me nt& Te c hni c alSt udi e s Addr e s s:E4 1 , Se c t o r 3 , No i da( U. P) www. i mt s i ns t i t ut e . c o m| Co nt a c t :9 1 +9 2 1 0 9 8 9 8 9 8