Presentation is loading. Please wait.

Presentation is loading. Please wait.

INTRODUCTION TO OBJECT ORIENTED CONCEPTS: By: Pavan D. M.

Similar presentations


Presentation on theme: "INTRODUCTION TO OBJECT ORIENTED CONCEPTS: By: Pavan D. M."— Presentation transcript:

1 INTRODUCTION TO OBJECT ORIENTED CONCEPTS: By: Pavan D. M.
MODULE 1 INTRODUCTION TO OBJECT ORIENTED CONCEPTS: By: Pavan D. M.

2 A Review of Structures In order to understand procedure-oriented programming systems, let us first recapitulate our understanding of structures in C. The Need for Structures: There are cases where the value of one variable depends upon that of another variable. Ex: date A date can be programmatically represented in C by three different integer variables taken together. Say, int d,m,y;//three integers for representing dates Here ‘d’, ‘m’, and ‘y’ represent the day of the month, the month, and the year, respectively. Although these three variables are not grouped together in the code, they actually belong to the same group. “The value of one variable may influence the value of the other two”.

3 Contd… In order to understand this clearly, consider a function next_day( ) that accepts the addresses of the three integers that represent a date and changes their values to represent the next day. The prototype of this function will be void next_day(int *,int *,int *); //function to calculate the next day Case 1) Suppose, d=1; m=1; y=2002; //1st January, 2002 Now, if we write next_day(&d,&m,&y); ‘d’ will become 2, ‘m’ will remain 1, and ‘y’ will remain 2002. Case 2) But if d=28; m=2; y=1999; //28th February, 1999 and we call the function as next_day(&d,&m,&y); ‘d’ will become 1, ‘m’ will become 3, and ‘y’ will remain 1999

4 Contd… Case 3) Again, if d=31; m=12; y=1999; //31st December, 1999
and we call the function as next_day(&d,&m,&y); ‘d’ will become 1, ‘m’ will become 1, and ‘y’ will become 2000. As you can see, ‘d’, ‘m’, and ‘y’ actually belong to the same group. A change in the value of one may change the value of the other two. But there is no language construct that actually places them in the same group. Thus, members of the wrong group may be accidentally sent to the function. d1=28; m1=2; y1=1999; //28th February, 1999 d2=19; m2=3; y2=1999; //19th March, 1999 next_day(&d1,&m1,&y1); //OK next_day(&d1,&m2,&y2); //What? Incorrect set passed!

5 Contd… As can be observed in Listing, there is nothing in the language itself that prevents the wrong set of variables from being sent to the function. Moreover, integer-type variables that are not meant to represent dates might also be sent to the function!. Let us try arrays to solve the problem. Suppose the next_day() function accepts an array as a parameter. Its prototype will be void next_day(int *); Let us declare date as an array of three integers. int date[3]; date[0]=28; date[1]=2; date[2]=1999; //28th February, 1999 Now, let us call the function as follows: next_day(date); Now date[0]=1, date[1]=3 and date[2]=1999 Although this method seems to work, it certainly appears unconvincing.

6 Contd…

7 Contd… After all any integer array can be passed to the function, even if it does not necessarily represent a date. There is no data type of date itself. Moreover, this solution of arrays will not work if the variables are not of the same type. The solution to this problem is to create a data type called date itself using structures struct date //a structure to represent dates { int d, m, y; }; Now, the next_day() function will accept the address of a variable of the structure date as a parameter. its prototype will be as follows: void next_day(struct date *);

8 Contd… struct date d1; d1.d=28; d1.m=2; d1.y=1999; next_day(&d1);

9 Contd… ‘d1.d’, ‘d1.m’, and ‘d1.y’ will be correctly set to 1, 3, and 1999, respectively. Since the function takes the address of an entire structure variable as a parameter at a time, there is no chance of variables of the different groups being sent to the function. Structure is a programming construct in C that allows us to put together variables that should be together. Library programmers use structures to create new data types. Application programs and other library programs use these new data types by declaring variables of this data type. struct date d1; They call the associated functions by passing these variables or their addresses to them. d1.d=31; d1.m=12; d1.y=2003; next_day(&d1); Finally, they use the resultant value of the passed variable further as per requirements. printf(“The next day is: %d/%d/%d\n”, d1.d, d1.m, d1.y); Output The next day is: 01/01/2004

10 Creating a New Data Type Using Structures
Creation of a new data type using structures is loosely a three-step process that is executed by the library programmer. Step 1: Put the structure definition and the prototypes of the associated functions in a header file /*Beginning of date.h*/ /*This file contains the structure definition and prototypes of its associated functions*/ struct date { int d,m,y; }; void next_day(struct date *); //get the next date void get_sys_date(struct date *); //get the current //system date /* Prototypes of other useful and relevant functions to work upon variables of the date structure */ /*End of date.h*/

11 Contd… Step 2: put the definition of the associated functions in a source code and create a library /*Beginning of date.c*/ /*This file contains the definitions of the associated functions*/ #include “date.h” void next_day(struct date * p) { //calculate the date that immediately follows the one //represented by *p and set it to *p. } void get_sys_date(struct date * p) //determine the current system date and set it to *p /* Definitions of other useful and relevant functions to work upon variables of the date structure */ /*End of date.c*/

12 Contd… Step 3: Provide the header file and the library, in whatever media, to other programmers who want to use this new data type. Using Structures in Application Programs The steps to use this new data type are as follows: Step 1: Include the header file provided by the library programmer in the source code. /*Beginning of dateUser.c*/ #include“date.h” void main( ) { . . . } /*End of dateUser.c*/

13 Contd… Step 2: Declare variables of the new data type in the source code. /*Beginning of dateUser.c*/ #include“date.h” void main( ) { struct date d; } /*End of dateUser.c*/

14 Contd… Step 3: Embed calls to the associated functions by passing these variables in the source code /*Beginning of dateUser.c*/ #include“date.h” void main() { struct date d; d.d=28; d.m=2; d.y=1999; next_day(&d); } /*End of dateUser.c*/

15 Contd…. Step 4: Compile the source code to get the object ¿ le.
Step 5: Link the object file with the library provided by the library programmer to get the executable or another library.

16 Procedure Oriented Programming System
The focus is on procedures. The problem is viewed as a sequence of things: Reading Calculating/Processing Printing Number of functions(procedures) are written to accomplish these tasks. Since the primary focus is on procedures, this approach is called Procedure – Oriented Programming(POP). In POP, the main task is taken up first and is divided into smaller logically independent components which in turn accomplish the specified sub tasks.

17 Typical structure of Procedure Oriented Programming

18 Contd… Programs are written with one or more procedures(functions).
Each procedure does a specific task. Data is passed openly(freely) from one procedure to another. Many important data items are placed as global so that they may be accessed by all the procedures. Each procedure may have its own local data.

19 Contd… The drawback with this programming pattern is that the data is not secure. It can be manipulated by any procedure. Associated functions that were designed by the library programmer do not have the exclusive rights to work upon the data. The complexity increases as the programs grow larger and complex. Compilers that implement POP systems do not prevent unauthorized functions from accessing/manipulating structure variables. EXAMPLE Now, let us look at the situation from the application programmer’s point of view. Consider an application of around 25,000 lines in which variables of this structure have been used quite extensively. During testing, it is found that the date being represented by one of these variables has become 29th February 1999…. The faulty piece of code that is causing this bug can be anywhere in the program. Therefore, debugging will involve a visual inspection of the entire code (of lines!) and will not be limited to the associated functions only.

20 Contd… The situation becomes especially grave if the execution of the code that is likely to corrupt the data is conditional. if(<some condition>) d.m++; //d is a variable of date structure… d.m may //become 13! The condition under which the bug-infested code executes may not arise during testing. While distributing his/her application, the application programmer cannot be sure that it would run successfully. Moreover, every new piece of code that accesses structure variables will have to be visually inspected and tested again to ensure that it does not corrupt the members of the structure. Let us think of a compiler that enables the library programmer to assign exclusive rights to the associated functions for accessing the data members of the corresponding structure. If this happens, then our problem is solved.

21 Contd… If a function which is not one of the intended associated functions accesses the data members of a structure variable, a compile-time error will result. To ensure a successful compile of his/her application code, the application programmer will be forced to remove those statements that access data members of structure variables. It is the lack of data security of procedure-oriented programming systems that led to object oriented programming systems (OOPS).

22 Object-Oriented Programming Systems
Object Oriented Programming (OOP) removes some of the flaws encountered in POP. In OOPs, the primary focus is on data rather than procedure. The data cannot be moved freely around the system. OOPs ties data more closely to the functions that operate on it, and protects it from accidental modification from outside functions. The functions cannot exist without data, and data need functions to give it a shape.

23 Organization of data and functions in OOP
Contd… Organization of data and functions in OOP

24 Contd… OOP allows decomposition of a problem into a number of entities called objects and then builds data and functions around these objects. Data is hidden and cannot be shared by outside functions. The data of an object can be accessed only by the functions associated with that object. The objects that are created may interact with each other via functions. OOPs follows Bottom-up approach, because the objects are created first and the data and functions around them are developed later.

25 Contd… Some of the striking features of object-oriented programming are: Emphasis is on data rather than procedure. Programs are divided into what are known as objects. Data structures are designed such that they characterize the objects. Functions that operate on the data of an object are tied together in the data structure. Data is hidden and cannot be accessed by external functions.. Objects may communicate with each other through functions. New data and functions can be easily added whenever necessary. Follows bottom-up approach in program design.

26 BASIC CONCEPTS OF Object Oriented Programming
Classes Objects Message Passing OOP Data Abstraction and Encapsulation Polymorphism Inheritance

27 Objects: Objects are basic run time entities in Object Oriented System. It may represent a person, a bank account, a place, a table of data, vectors, etc. Objects should be chosen such that they match closely with real-world objects. Ex: Name, DOB, Address, Age. If these details are required for student, create STUDENT object. If these details are required for customer, create CUSTOMER object. If these details are required for employee, create EMPLOYEE object. Objects occupy space in the memory and have an associated address. When a program is executed, the objects interact by sending messages to one another. Ex: If “CUSTOMER” and “ACCOUNT” are two objects, then the CUSTOMER object may send a message to the ACCOUNT object requesting for bank balance.

28 Contd… Objects contain both data and operations that manipulate these data. Objects can interact without having to know details of each other’s data or code. It is sufficient to know the type of message accepted, and the type of response returned by the objects.

29 Classes: A class is a collection of objects of similar type.
The entire set of data and code of an object can be made a user defined data type with the help of a class. Once a class is defined, any number of objects belonging to that class can be created.

30 Contd…

31 Encapsulation: The wrapping up of data and functions into a single unit (called class) is known as Encapsulation. It hides the implementation details of an object from its users. Encapsulation prevents unauthorized access of data or functionality. The data is not accessible to the outside world, and only functions which are wrapped in the class can access it. This is called data hiding or information hiding.

32 Data Abstraction: Abstraction refers to the act of representing essential features without including background details or explanations. It separates unnecessary details or explanations so as to reduce complexities of understanding requirements.

33 Inheritance: Inheritance is the process by which objects of one class acquire the properties of objects of another class. Hierarchical Classification Reusability – adding additional features to an existing class without modifying it. That is, deriving a new class from the existing one. The new class will have the combined features of both the classes. New class is also called as Derived class and existing class is called as Base Class.

34 Contd…

35 Polymorphism: (having many forms)
Ability to take more than one form. The polymorphism is an ability to access different implementations of a function using the same name. Ex: Function to perform addition operation Input Output Two integer numbers integer sum Two float number float sum Two strings constants concatenation

36 Contd… Addition Operation add(int, int) add(float, float)
add(string, string)

37 Contd… Operator Overloading: The process of making an operator to exhibit different behaviours in different instances. Function Overloading: Using a single function name to perform different types of tasks.

38 Contd… Dynamic Binding:
Dynamic binding (late binding) means that the code associated with a procedure call is not known until the time of the call at run-time. Usually associated with Polymorphism and Inheritance. At run-time, the code matching the object under current reference will be called.

39 Message Passing: Set of objects communicate with each other.
Steps involved: 1. Creating classes that define objects and their behaviour. 2. Creating objects from class definitions. 3. Establishing communication among objects. Objects communicate with one another by sending and receiving information. A message for an object is a request for execution of a procedure, and therefore will invoke a function(procedure) in the receiving object that generates the desired result. Message Passing involves specifying the name of the object, the name of the function(message) and the information to be sent.

40 employee.salary(name);
Contd… Objects have a life cycle. They can be created and destroyed. Communication with an object is feasible as long as it is alive. employee.salary(name); Object Information message

41 Comparison of C++ with C
Procedure Oriented Programming Object Oriented Programming In POP, program is divided into small parts called functions. In OOP, program is divided into parts called objects. In POP, Importance is not given to data but to functions as well as sequence of actions to be done. In OOP, Importance is given to the data rather than procedures or functions because it works as a real world. POP follows Top Down approach. OOP follows Bottom Up approach. POP does not have any access specifier. OOP has access specifiers named Public, Private, Protected, etc. In POP, Data can move freely from function to function in the system. In OOP, objects can move and communicate with each other through member functions. To add new data and function in POP is not so easy. OOP provides an easy way to add new data and function. Comparison of C++ with C

42 Object Oriented Programming
Contd… Procedure Oriented Programming Object Oriented Programming In POP, Most function uses Global data for sharing that can be accessed freely from function to function in the system. In OOP, data can not move easily from function to function, it can be kept public or private so we can control the access of data. POP does not have any proper way for hiding data so it is less secure. OOP provides Data Hiding so provides more security. In POP, Overloading is not possible. In OOP, overloading is possible in the form of Function Overloading and Operator Overloading. Example of POP are : C, VB, FORTRAN, Pascal. Example of OOP are : C++, JAVA, VB.NET, C#.NET.

43 C and C++ Bjarne Stroustrup : Developer of C++ is a Danish computer scientist C++ was developed by Bjarne Stroustrup in 1979. C was developed by Dennis Ritchie between 1969 and 1973 at AT&T Bell Labs.

44 Console Input/Output in C++
Console Output (cout<<) The standard output by default is the screen. cout (prounced as “see-out”) is an object of the class ostream. cout = console output (usually Monitor/Screen) The << symbol – left shift operator (two less than symbols) – It operates as “insertion” operator. It’s a binary operator, which takes two operands. cout<<content to be printed; The file ‘iostream.h’ need to be included in the source code for successful compilation of a program. It does not need any format specifiers.

45 Examples cout << "Output sentence"; // prints Output sentence on screen cout << 120; // prints number 120 on screen cout << x; // prints the value of x on screen Multiple insertion operations (<<) may be chained in a single statement: cout << "This " << " is a " << "single C++ statement"; Output: This is a single C++ statement cout << "I am " << age << " years old and my zipcode is " << zipcode; If age=30 and zipcode=586101, What is the output? Output: I am 30 years old and my zipcode is

46 Contd… What cout does not do automatically is add line breaks at the end, unless instructed to do so. For example, cout << "This is a sentence."; cout << "This is another sentence.";  The output would be in a single line, without any line breaks in between. This is a sentence.This is another sentence.  Line breaks can be added in 2 ways: 1. \n or 2. endl

47 Example Output: First sentence. Second sentence. Third sentence.
cout << "First sentence.\n"; cout << "Second sentence.\nThird sentence."; The endl manipulator can also be used to break lines This would print: First sentence. Second sentence. cout << "First sentence." << endl; cout << "Second sentence." << endl;

48 Console Input (cin>>)
The standard input by default is the Keyboard. cin (prounced as “see-in”) is an object of the class istream. cin = console input (usually Keyboard) The >> symbol – right shift operator (two greater than symbols) – It operates as “extraction” operator. It’s a binary operator, which takes two operands. cin>>content to be read; The file ‘iostream.h’ need to be included in the source code for successful compilation of a program. It does not need any format specifiers.

49 Example: int age; cin >> age;
Extractions on cin can also be chained to request more than one datum in a single statement . cin >> a >> b; This is equivalent to In both cases, the user is expected to introduce two values, one for variable a, and another for variable b. Any kind of space is used to separate two consecutive input operations; this may either be a space, a tab, or a new-line character. cin >> a; cin >> b;

50 Example

51 Variables in C++ Variables in C++ can be declared anywhere inside a function and not necessarily at its very beginning. #include<iostream.h> void main() { int n1, n2; cout<<“Enter 2 nos”; cin>>n1; cin>>n2; int sum; sum=n1+n2; cout<<“Sum = “<<sum<<endl; getch(): }

52 Reference Variables in C++
How are assignment operations such as ‘x=y’ executed during run time? A detailed answer to these questions is beyond the scope. A brief study is, nevertheless, possible and necessary for a good understanding of reference variables. The OS maintains the addresses of each variable as it allocates memory for them during run time. In order to access the value of a variable, the OS first finds the address of the variable and then transfers control to the byte whose address matches that of the variable. Suppose the following statement is executed (‘x’ and ‘y’ are integer type variables). x=y; The Step Followed are

53 Contd.. 1. The OS first finds the address of ‘y’. 2. The OS transfers control to the byte whose address matches this address. 3. The OS reads the value from the block of four bytes that starts with this byte (most C++ compilers cause integer-type variables to occupy four bytes during run time and we will accept this value for our purpose). 4. The OS pushes the read value into a temporary stack. 5. The OS finds the address of ‘x’. 6. The OS transfers control to the byte whose address matches this address. 7. The OS copies the value from the stack, where it had put it earlier, into the block of four bytes that starts with the byte whose address it has found above (address of ‘x’).

54 Contd… Notice that addresses of the variables on the left as well as on the right of the assignment operator are determined. However, the value of the right-hand operand is also determined. The expression on the right must be capable of being evaluated to a value. A reference variable is nothing but a reference for an existing variable. It shares the memory location with an existing variable. The syntax for declaring a reference variable is as follows: <data-type> & <ref-var-name>=<existing-var-name>; float total = 100; float & sum = total; For ex, If we make the variable sum a reference to the variable total, then sum and total can be used interchangeably to represent that variable.

55 Contd… /*Beginning of reference01.cpp*/ #include<iostream.h> void main() { int x; x=10; cout<<x<<endl; int & iRef=x; //iRef is a reference to x iRef=20; x++; //same as iRef++; cout<<iRef<<endl; } Output: 20 21

56 Contd… /*Beginning of reference02.cpp*/ #include<iostream.h>
Reference variables must be initialized at the time of declaration. The value of a reference variable can be read in the same way as the value of an ordinary variable is read. /*Beginning of reference02.cpp*/ #include<iostream.h> void main() { int x,y; x=10; int & iRef=x; y=iRef; //same as y=x; cout<<y<<endl; y++; //x and iRef unchanged cout<<x<<endl<<iRef<<endl<<y<<endl; } Output: 10 11

57 Contd… /*Beginning of reference03.cpp*/ #include<iostream.h>
A reference variable can be a function argument and thus change the value of the parameter that is passed to it in the function call. /*Beginning of reference03.cpp*/ #include<iostream.h> void increment(int &); //formal argument is a reference //to the passed parameter void main() { int x; x=10; increment(x); cout<<x<<endl; } void increment(int & r) O/P : 11 r++; //same as x++; /*End of reference03.cpp*/

58 Contd… /*Beginning of reference04.cpp*/ #include<iostream.h>
int & larger(int &, int &); int main() { int x,y; x=10; y=20; int & r=larger(x,y); r=-1; cout<<x<<endl<<y<<endl; } int & larger(int & a, int & b) if(a>b) //return a reference to the larger parameter return a; else return b; O/P : 10 } /*End of reference04.cpp*/

59 In the foregoing listing, ‘a’ and ‘x’ refer to the same memory location while ‘b’ and ‘y’ refer to the same memory location. From the larger() function, a reference to ‘b’, that is, reference to ‘y’ is returned and stored in a reference variable ‘r’. The larger() function does not return the value ‘b’ because the return type is int & and not int. Thus, the address of ‘r’ becomes equal to the address of ‘y’. Consequently, any change in the value of ‘r’ also changes the value of ‘y’. #include<iostream.h> int & larger(int &, int &); int main() { int x,y; x=10; y=20; larger(x,y)=-1; cout<<x<<endl<<y<<endl; } int & larger(int & a, int & b) { if(a>b) //return a reference to the larger parameter return a; else return b; }

60 Contd… transfer control to the byte that has that address,
If the compiler finds the name of a non-constant variable on the left of the assignment operator in the source code, it writes instructions in the executable to determine the address of the variable, transfer control to the byte that has that address, and write the value on the right of the assignment operator into the block that begins with the byte found above. If the compiler finds the name of a variable on the right of the assignment operator in the source code, it writes instructions in the executable to transfer control to the byte that has that address, read the value from the block that begins with the byte found above, and push the read value into the stack.

61 return_type function_name(argument_list);
Function Prototyping Syntax: return_type function_name(argument_list);

62 Contd… Ex: int add ( int, int );
This prototype indicates that the add() function returns a value of integer type and takes two parameters both of integer type. Function prototype is also a statement, it must be ended with semi-colon. Providing names to the formal arguments in function prototype is optional.

63 Contd…

64 Contd… Why is Prototyping important?
The return value of a function is handled correctly. Correct number and type of arguments are passed to a function. Ex: The prototype tells the compiler that the add() function returns an integer type value. Thus, the compiler knows how many bytes have to be retrieved from the place where the add() function is expected to write its return value and how these bytes are to be interpreted.

65 Contd… In the absence of prototypes, the compiler will have to assume the type of the returned value. If the assumption and the actual return value are incompatible, then the compiler will report an error against the function definition and not the function call. Thus, function prototyping guarantees protection from errors arising out of incorrect function calls. The function prototype also tells the compiler that the add() function accepts two parameters. If the program fails to provide such parameters, compiler detects an error. Function prototyping produces automatic type conversion whenever appropriate.

66 Example #include<iostream.h>
int add(int,int); //function prototype void main() { int x,y,z; cout<<“Enter a number: ”; cin>>x; cout<<“Enter another number: ”; cin>>y; z=add(x,y); //function call cout<<z<<endl; } int add(int a,int b) { return (a+b); }

67 Contd… if the function definition is in a different file to be compiled separately, then no compile-time errors will arise. Instead, wrong results will arise during run time. /*Beginning of def.c*/ /*function definition*/ struct abc { char a; int b; float c; }; struct abc test() struct abc a1; a1.a=‘x’; a1.b=10; a1.c=1.1; return a1; } /*End of def.c*/ /*Beginning of driver.c*/ void main() { int x; x=test(); //no compile time error!! printf(“%d”,x); } /*End of driver.c*/ Output: 1688 The compiler will not be able to convert a struc abc to an integer. Thus, function prototyping guarantees protection from errors arising out of incorrect function calls.

68 Contd… What happens if the function prototype and the function call do not match? Such a situation cannot arise. Both the function prototype and the function definition are created by the same person, that is, the library programmer. The function’s prototype also tells the compiler that the add() function accepts two parameters. If the program fails to provide such parameters, the prototype enables the compiler to detect the error. A compiler that does not enforce function prototyping will compile a function call in which an incorrect number and/or type of parameters have been passed. Runtime errors will arise as in the foregoing case. Finally, function prototyping produces automatic-type conversion wherever appropriate. We take the case of compilers that do not enforce prototyping. Suppose, a function expects an integer-type value (assuming integers occupy four bytes) but a value of double type (assuming doubles occupy eight bytes) is wrongly passed. During run time, the value in only the first four bytes of the passed eight bytes will be extracted. This is obviously undesirable. However, the C++ compiler automatically converts the double-type value into an integer type. This is because it inevitably encounters the function prototype before encountering the function call and therefore knows that the function expects an integer-type value.

69 Function Overloading C++ allows two or more functions to have the same name, but different signature. The compiler decides which function is to be called based upon the number, type, and sequence of parameters that are passed to the function call.

70 Example A function call first matches the prototype having the same number and type of arguments and then calls the appropriate function for execution.

71 Contd… The compiler first tries to find an exact match in which the types of actual arguments are the same, and use that function. If an exact match is not found, the compiler uses the integral promotions to the actual arguments, such as: char to float float to double to find a match. If the conversion is possible to have multiple matches, then the compiler will generate an error message. Ex: long square(long n) double square(double x) A function call such as square(10) will cause an error because int can be converted to either long or double, thereby creating an ambiguous situation as to which version of square() should be called.

72 Example /*Beginning of funcOverload.cpp*/ #include<iostream.h>
int add(int,int); //first prototype int add(int,int,int); //second prototype void main() { int x,y; x=add(10,20); //matches first prototype y=add(30,40,50); //matches second prototype cout<<x<<endl<<y<<endl; } int add(int a,int b) { return(a+b); } int add(int a,int b,int c) return(a+b+c); Output 30 120

73 Contd… The two function prototypes at the beginning of the program tell the compiler the two different ways in which the add() function can be called. When the compiler encounters the two distinct calls to the add() function, it already has the prototypes to satisfy them both. Thus, the compilation phase is completed successfully. The compiler decides which function is to be called based upon the number, type, and sequence of parameters that are passed to the function call. The first function call, x=add(10,20); it decides that the function that takes two integers as formal arguments is to be executed. Accordingly, the linker then searches for the definition of the add() function where there are two integers as formal arguments. Similarly, the second call to the add() function y=add(30,40,50); is also handled by the compiler and the linker.

74 Contd… Default Values for Formal Arguments of Functions
Function overloading is also known as function polymorphism because, just like polymorphism in the real world where an entity exists in more than one form, the same function name carries different meanings. Default Values for Formal Arguments of Functions It is possible to specify default values for some or all of the formal arguments of a function. If no value is passed for an argument when the function is called, the default value specified for it is passed. If parameters are passed in the normal fashion for such an argument, the default value is ignored.

75 Contd… /*Beginning of defaultArg.cpp*/ #include<iostream.h>
int add(int,int,int c=0); //third argument has default value void main() { int x,y; x=add(10,20,30); //default value ignored y=add(40,50); //default value taken for the third parameter cout<<x<<endl<<y<<endl; } int add(int a,int b,int c) return (a+b+c); Output 60 90

76 Example #include<iostream.h>
int add(int,int b=0,int c=0); //second and third arguments have default values void main() { int x,y,z; x=add(10,20,30); //all default values ignored y=add(40,50); //default value taken for the third argument z=add(60); //default value taken for the second and the third arguments cout<<x<<endl<<y<<endl<<z<<endl; } int add(int a,int b,int c) return (a+b+c);

77 Inline Functions Inline functions are used to increase the speed of execution of the executable files. C++ inserts calls to the normal functions and the inline functions in different ways in an executable. An inline function is a function whose compiled code is ‘in line’ with the rest of the program. That is, the compiler replaces the function call with the corresponding function code. With inline code, the program does not have to jump to another location to execute the code and then jump back. Inline functions, thus, run a little faster than regular functions. prefix the definition of the function with the inline keyword and define the function before all functions that call it, that is, define it in the header file itself.

78 Example of code in non-inline function

79 Example #include<iostream.h> inline double cube(double x) { return x*x*x; } void main() { double a,b; double c=13.0; a=cube(5.0); b=cube( ); cout<<a<<endl; cout<<b<<endl; cout<<cube(c++)<<endl; cout<<c<<endl; }

80 Introduction to Classes and Objects
Classes are to C++ what structures are to C. Both provide the library programmer a means to create new data types. Issues faced while programming in C : In C, the library programmer creates structures. He/she also provides a set of tested bug-free functions that correctly manipulate the data members of structure variables. The Date structure and its accompanying functions may be perfect. However, there is absolutely no guarantee that the client programs will use only these functions to manipulate the members of variables of the structure. struct Date d1; setDate(&d1); //assign system date to d1. printf(“%d”,d1.month); d1.month = 13; The bug arising out of the last line of the main() function above is easily detected even by a visual inspection. Nevertheless, the same will certainly not be the case if the code is around 25,000 lines long.

81 Contd… Notice that the absence of a facility to bind the data and the code that can have the exclusive rights to manipulate the data can lead to difficult-to-detect run- time bugs. C does not provide the library programmer with the facilities to encapsulate data, to hide data, and to abstract data. The C++ compiler provides a solution to this problem. Structures (the struct keyword) have been redefined to allow member functions also.

82 Example void main() { Distance d1,d2; d1.setFeet(2);
#include<iostream.h> struct Distance { int iFeet; float fInches; void setFeet(int x) iFeet=x; } int getFeet() return iFeet; void setInches(float y) fInches=y; float getInches() return fInches; }; void main() { Distance d1,d2; d1.setFeet(2); d1.setInches(2.2); d2.setFeet(3); d2.setInches(3.3); cout<<d1.getFeet()<<“ ”<<d1.getInches()<<endl; cout<<d2.getFeet()<<“ ”<<d2.getInches()<<endl; }

83 Contd.. First, we must notice that functions have also been defined within the scope of the structure definition. This means that not only the member data of the structure can be accessed through the variables of the structures but also the member functions can be invoked. The struct keyword has actually been redefined in C++. Member functions are invoked in much the same way as member data are accessed, that is, by using the variable-to-member access operator. it is d1.iFeet that gets the value of 2. On the other hand, it is d2.iFeet that gets the value of 3 when the fourth line is invoked. Each structure variable contains a separate copy of the member data within itself. However, only one copy of the member function exists. However, in the above example, note that the member data of structure variables can still be accessed directly. d1.iFeet=2; //legal!!

84 Private and Public Members
We have put together the data and functions that work upon the data but we have not been able to give exclusive rights to these functions to work upon the data. Problems in code debugging can still arise as before. Specifying member functions as public but member data as private obtains the advantage. #include<iostream.h> struct Distance { private: int iFeet; float fInches; public: void setFeet(int x) iFeet=x; //LEGAL: private member accessed by //member function } int getFeet() return iFeet; void setInches(float y) fInches=y; float getInches() return fInches; }; void main() { Distance d1,d2; d1.setFeet(2); d1.setInches(2.2); d2.setFeet(3); d2.setInches(3.3); d1.iFeet++; //ERROR!!: private member //accessed by non-member function cout<<d1.getFeet()<<“”<<d1.getInches()<<endl; cout<<d2.getFeet()<<“ ”<<d2.getInches()<<endl; }

85 Example First, let us have a close look at the modified definition of the structure Distance. Two new keywords, private and public have been introduced in the definition of the structure. Their presence in the foregoing example tells the compiler that iFeet and fInches are private data members of variables of the structure Distance and the member functions are public. Thus, values of iFeet and fInches of each variable of the structure Distance can be accessed/ modified only through member functions of the structure and not by any non-member function in the program (again note that it is the iFeet and fInches of the invoking object that are accessed/modified by the member functions). Any attempt to violate this restriction is prevented by the compiler because that is how the C++ compiler recognizes the private keyword. Since the member functions are public, they can be invoked from any part of the program. The keywords private and public are also known as access modifiers or access specifiers because they control the access to the members of structures. C++ introduces a new keyword class as a substitute for the keyword struct. In a structure, members are public by default .

86 Example struct Distance { private: int iFeet; float fInches; public:
void setFeet(int x) iFeet=x; } int getFeet() return iFeet; void setInches(float y) fInches=y; float getInches() return fInches; }; struct Distance { void setFeet(int x) //public by default iFeet=x; } int getFeet() //public by default return iFeet; void setInches(float y) //public by default fInches=y; float getInches() //public by default return fInches; private: int iFeet; float fInches; };

87 Example On the other hand, class members are private by default. This is the only difference between the class keyword and the struct keyword. class Distance { int iFeet; //private by default float fInches; //private by default public: void setFeet(int x) iFeet=x; } int getFeet() return iFeet; void setInches(float y) fInches=y; float getInches() return fInches; };

88 Objects Variables of classes are known as objects.
An object of a class occupies the same amount of memory as a variable of a structure that has the same data members. /*Beginning of objectSize.cpp*/ #include<iostream.h> struct A { char a; int b; float c; }; class B //a class with the same data members void main() cout<<sizeof(A)<<endl<<sizeof(B)<<endl; } Output 9

89 Scope Resolution Operator
It is possible and usually necessary for the library programmer to define the member functions outside their respective classes. The scope resolution operator makes this possible. void Distance::setFeet(int x) //definition { iFeet=x; } int Distance::getFeet() //definition return iFeet; void Distance::setInches(float y) //definition fInches=y; float Distance::getInches() //definition return fInches; class Distance { int iFeet; float fInches; public: void setFeet(int); //prototype only int getFeet(); //prototype only void setInches(float); //prototype only float getInches(); //prototype only };

90 Contd… We can observe that the member functions have been only prototyped within the class; they have been defined outside. The scope resolution operator signifies the class to which they belong. The class name is specified on the left-hand side of the scope resolution operator.

91 Creating Libraries Using the Scope Resolution Operator
Its a three-step process Step 1: Place the class definition in a header file. /*Beginning of Distance.h*/ /*Header file containing the definition of the Distance class*/ class Distance { int iFeet; float fInches; public: void setFeet(int); //prototype only int getFeet(); //prototype only void setInches(float); //prototype only float getInches(); //prototype only }; /*End of Distance.h*/

92 Contd… Step 2: Place the definitions of the member functions in a C++ source file (the library source code). A file that contains definitions of the member functions of a class is known as the implementation file of that class. Compile this implementation file and put in a library. /*Beginning of Distlib.cpp*/ /*Implementation file for the class Distance*/ #include“Distance.h” void Distance::setFeet(int x) //definition { iFeet=x; } int Distance::getFeet() //definition return iFeet; void Distance::setInches(float y) //definition fInches=y; float Distance::getInches() //definition return fInches; /*End of Distlib.cpp*/

93 Contd… Step 3: Provide the header file and the library, in whatever media, to other programmers who want to use this new data type.

94 Using Classes in Application Programs
Step 1: Include the header file provided by the library programmer in their source code. /*Beginning of Distmain.cpp*/ #include“Distance.h” void main() { } /*End of Distmain.cpp*/ Step 2: Declare variables of the new data type in their source code. Distance d1,d2;

95 Contd… Step 3: Embed calls to the associated functions by passing these variables in their source code. /*Beginning of Distmain.cpp*/ /*A sample driver program for creating and using objects of the class Distance*/ #include<iostream.h> #include“Distance.h” void main() { Distance d1,d2; d1.setFeet(2); d1.setInches(2.2); d2.setFeet(3); d2.setInches(3.3); cout<<d1.getFeet()<<“ ”<<d1.getInches()<<endl; cout<<d2.getFeet()<<“ ”<<d2.getInches()<<endl; } /*End of Distmain.cpp*/

96 Contd… Step 4: Compile the source code to get the object file.
Step 5: Link the object file with the library provided by the library programmer to get the executable or another library.

97 this Pointer The facility to create and call member functions of class objects is provided by the C++ compiler. The compiler does this by using a unique pointer known as the this pointer. The this pointer is always a constant pointer. The this pointer always points at the object with respect to which the function was called. After the compiler has ascertained that no attempt has been made to access the private members of an object by non-member functions, it converts the C++ code into an ordinary C language code as follows: It converts the class into a structure with only data members as follows. Before After struct Distance { int iFeet; float fInches; }; class Distance { int iFeet; float fInches; public: void setFeet(int); //prototype only int getFeet(); //prototype only void setInches(float); //prototype only float getInches(); //prototype only };

98 Contd… 2. It puts a declaration of the this pointer as a leading formal argument in the prototypes of all member functions as follows. Before void setFeet(int); After void setFeet(Distance * const, int); int getFeet(); int getFeet(Distance * const); void setInches(float); void setInches(Distance * const, float); float getInches(); float getInches(Distance * const);

99 Contd… 3. It puts the definition of the this pointer as a leading formal argument in the definitions of all member functions as follows. It also modifies all the statements to access object members by accessing them through the this pointer using the pointer-to-member access operator (->). After void setFeet(Distance * const this, int x) { this->iFeet=x; } Before void Distance::setFeet(int x) { iFeet=x; } Before int Distance::getFeet() { return iFeet; } After int getFeet(Distance * const this) { return this->iFeet; }

100 Contd… The scope resolution operator is also an operator. Just like any other operator, it operates upon its operands. The scope resolution operator is a binary operator, that is, it takes two operands. Based upon this information, the scope resolution operator inserts a constant operator of the correct type as a leading formal argument to the function on its right. For example, if the class name is Distance, as in the above case, the compiler inserts a pointer of type Distance * const as a leading formal argument to the function on its right. Before float Distance::getInches() { return fInches; } After float getInches(Distance * const this) { return this->fInches; }

101 Contd… 4. It passes the address of invoking object as a leading parameter to each call to the member functions as follows. After setFeet(&d1,1); Before d1.setFeet(1); After setInches(&d1,1.1); Before d1.setInches(1.1); Before cout<<d1.getFeet()<<endl; After cout<<getFeet(&d1)<<endl; After cout<<getInches(&d1)<<endl; Before cout<<d1.getInches()<<endl;

102 Contd… It is evident that the this pointer should continue to point at the same object— the object with respect to which the member function has been called— throughout its lifetime. For this reason, the compiler creates it as a constant pointer. /*Beginning of Distlib.cpp*/ #include“Distance.h” Distance Distance::add(Distance dd) { Distance temp; temp.iFeet=iFeet+dd.iFeet; //legal to access both //temp.iFeet and dd.iFeet temp.fInches=fInches+dd.fInches; //ditto return temp; } /* definitions of the rest of the functions of class Distance */ /*End of Distlib.cpp*/ /*Beginning of Distance.h*/ class Distance { /* rest of the class Distance */ Distance add(Distance); }; /*End of Distance.h*/

103 Contd… Oooooooooooooooooooooooooooooooooooo
/*Beginning of Distmain.cpp*/ #include<iostream.h> #include“Distance.h” void main() { Distance d1,d2,d3; d1.setFeet(1); d1.setInches(1.1); d2.setFeet(2); d2.setInches(2.2); d3=d1.add(d2); cout<<d3.getFeet()<<“’-”<<d3.getInches()<<“’’\n”; } /*End of Distmain.cpp*/ Output 3-3.3

104 Contd... The definition of Distance :: add() function, after the previously described conversion by the compiler is carried out, will appear as follows. Distance add(Distance * const this, Distance dd) { Distance temp; temp.iFeet=this->iFeet+dd.iFeet; temp.fInches=this->fInches+dd.fInches; return temp; } When this function is called from the main() function with respect to ‘d1’, the this pointer points at ‘d1’. Thus, it is the private data member of ‘d1’ that is being accessed in the second and third lines of the add() function. So, now we can Declare a class Define member data and member functions Make members private and public Declare objects and call member functions with respect to objects

105 What advantages does all this lead to?
The advantage that library programmers can now derive from this arrangement is epitomized in the following observation: An executable file will not be created from a source code in which private data members of an object have been accessed by non-member functions

106 Contd… Once again, the importance of compile-time errors over run-time errors is emphasized. A pure C compiler would not recognize this statement as an invalid access. Thus, creating bug-free executables is difficult and unreliable in C. This is due to the absence of language constructs that enforce data security. On the other hand, a C++ compiler that also detects invalid access of private data members would immediately throw an error during compile time itself and prevent the creation of the executable. Thus, creating bug-free executables is easier and more reliable in C++ than in C. This is due to the presence of language constructs that enforce data security.

107 Data Abstraction Data abstraction is a virtue by which an object hides its internal operations from the rest of the program. It makes it unnecessary for the client programs to know how the data is internally arranged in the object. Now, in order to understand this concept, let us take an example in C++. The library programmer, who has designed the Distance class, wants to ensure that the fInches portion of an object of the class should never exceed 12

108 Example If a value larger than 12 is specified by an application programmer while calling the Distance::setInches() function, the logic incorporated within the definition of the function should automatically increment the value of iFeet and decrement the value of fInches by suitable amounts. void Distance::setInches(float y) { fInches=y; if(fInches>=12) iFeet+=fInches/12; fInches-=((int)fInches/12)*12; } Here, we notice that an application programmer need not send values less than 12 while calling the Distance::setInches() function. The default logic within the Distance::setInches() function does the necessary adjustments. This is an example of data abstraction.

109 Contd… Similarly, the definition of the Distance::add() function should also be modified as follows by the library programmer. Here, it can be assumed that the value of fInches portion of neither the invoking object nor the object appearing as formal argument (‘dd’) can be greater than 12. Distance Distance::add(Distance dd) { Distance temp; temp.iFeet=iFeet+dd.iFeet; temp.setInches(fInches+dd.fInches); return temp; } d1.setFeet(1); d1.setInches(9.5); d2.setFeet(2); d2.setInches(5.5); d3=d1.add(d2); then the value of d3.fInches will become 3 (not 15) and the value of d3.iFeet will become 4 (not 3).

110 Contd… It has already been mentioned that real-world objects never attain an invalid state. They also do not start in an invalid state. Let us continue with our earlier example—the Distance class. Recollect that it is the library programmer’s intention to ensure that the value of fInches portion of none of the objects of the class Distance should exceed 12. /*Beginning of DistJunk.cpp*/ #include<iostream.h> #include“Distance.h” void main() { Distance d1; cout<<d1.getFeet()<<“ ”<<d1.getInches()<<endl; } /*End of DistJunk.cpp*/ Output

111 Contd… As you can see, the value of fInches of ‘d1’ is larger than 12! This happened because the value of both iFeet and fInches automatically got set to junk values when ‘d1’ was allocated memory and the junk value is larger than 12 for d1.fInches. Thus, the objective of the library programmer to keep the value of fInches less than 12 has not yet been achieved. It would be unrealistic to expect that an application programmer will explicitly initialize each object that is declared. Distance d1; d1.setFeet(0); //initialization d1.setInches(0.0); //initialization Data abstraction is effective due to data hiding only. On the other side of the coin, in C language, life becomes difficult for an application programmer also. If a certain member of a structure variable acquires an invalid or a wrong value, he/she has to hunt through the entire source code to detect the bug. Perfect definitions of the member functions are guaranteed to achieve their objective because of data hiding.

112 Explicit Address Manipulation
An application programmer can manipulate the member data of any object by explicit address manipulation. /*Beginning of DistAddrManip.cpp*/ #include“Distance.h” #include<iostream.h> void main() { Distance d1; d1.setFeet(256); d1.setInches(2.2); char * p=(char *)&d1; //explicit address manipulation *p=1; //undesirable but unpreventable cout<<d1.getFeet()<<“ ”<<d1.getInches()<<endl; } /*End of DistAddrManip.cpp*/ However, such explicit address manipulation by an application programmer cannot be prevented.

113 Arrow Operator Member functions can be called with respect to an object through a pointer pointing at the object. The arrow operator (->) does this. /*Beginning of PointerToMember.cpp*/ #include<iostream.h> #include“Distance.h” void main() { Distance d1; //object Distance * dPtr; //pointer dPtr=&d1; //pointer initialized /*Same as d1.setFeet(1) and d1.setInches(1.1)*/ dPtr->setFeet(1); //calling member functions dPtr->setInches(1.1); //through pointers /*Same as d1.getFeet() and d1.getInches()*/ cout<<dPtr->getFeet()<<“ ”<<dPtr->getInches()<<endl; } /*End of PointerToMember.cpp*/

114 Contd… It is interesting to note that just like the dot (.) operator, the definition of the arrow (->) operator has also been extended in C++. It takes not only data members on its right as in C, but also member functions as its right-hand side operand. If the operand on its right is a data member, then the arrow operator behaves just as it does in C language. However, if it is a member function of a class where a pointer of the same class type is its left-hand side operand, then the compiler simply passes the value of the pointer as an implicit leading parameter to the function call. dPtr->setFeet(1); setFeet(dPtr,1); Now, the value of dPtr is copied into the this pointer. Therefore, the this pointer also points at the same object at which dPtr points.

115 Calling One Member Function from Another
One member function can be called from another. /*Beginning of NestedCall.cpp*/ class A { int x; public: void setx(int); void setxindirect(int); }; void A::setx(int p) x=p; } void A::setxindirect(int q) setx(q); void main() { A A1; A1.setxindirect(1); } /*End of NestedCall.cpp*/

116 Contd… The call to the A::setxindirect() function changes from
setxindirect(&A1,1); The definition of the A::setxindirect() function changes from void A:: setxindirect(int q) { setx(q); } void setxindirect(A * const this, int q) this->setx(q); //calling function through a pointer

117 Contd… which, in turn, changes to
void setxindirect(A * const this, int q) { setx(this,q); //action of arrow operator }

118 Member Functions and Member Data
Overloaded Member Functions: Member functions can be overloaded just like non-member functions. void A::show() { cout<<“Hello\n”; } void A::show(int x) for(int i=0;i<x;i++) void main() A A1; A1.show(); //first definition called A1.show(3); //second definition called #include<iostream.h> class A { public: void show(); void show(int); }; Output Hello

119 Contd… Consider the following example void show(A * const);
void show(B * const); class A { public: void show(); }; class B A function of the same name show() is defined in both the classes—‘A’ and ‘B’. The signature also appears to be the same. But with our knowledge of the this pointer, we know that the signatures are actually different.

120 Contd.. Without the facility of function overloading, it would not be possible for us to have two functions of the same name in different classes. Without the facility of function overloading, choice of names for member functions would become more and more restricted. Hence C++ enlabes with the concept of Dynamic Polymorphism. Default Values for Formal Arguments of Member Functions – Over Page no: 65 from Sourav Sahay Inline Member Functions – Over Page no: 66 from Sourav Sahay

121 Default Values for Formal Arguments of Member Functions Example
#include<iostream.h> class A { public: void show(int=1); }; void A::show(int p) for(int i=0;i<p;i++) cout<<“Hello\n”; } void main() A A1; A1.show(); //default value taken A1.show(3); //default value overridden /*End of memFuncDefault.cpp*/ Output Hello

122 Constant Member Functions
Let us consider this situation. The library programmer desires that one of the member functions of his/her class should not be able to change the value of member data. This function should be able to merely read the values contained in the data members, but not change them. However, he/she fears that while defining the function he/she might accidentally write the code to do so. In order to prevent this, he/she seeks the compiler’s help. If he/she declares the function as a constant function. And thereafter attempts to change the value of a data member through the function, the compiler throws an error. Let us consider the class Distance. The Distance::getFeet(), Distance::getInches(), and the Distance::add() functions should obviously be constant functions. They should not change the values of iFeet or fInches members of the invoking object even by accident. Member functions are specified as constants by suffixing the prototype and the function definition header with the const keyword.

123 Example /*Header file containing the definition of the Distance
/*Beginning of Distlib.cpp*/ /*Implementation file for the class Distance*/ #include“Distance.h” void Distance::setFeet(int x) { iFeet=x; } Int Distance::getFeet() const //constant function iFeet++; //ERROR!! return iFeet; void Distance::setInches(float y) fInches=y; float Distance::getInches() const //constant function fInches=0.0; //ERROR!! return fInches; Distance Distance::add(Distance dd) const //constant function Distance temp; temp.iFeet=iFeet+dd.iFeet; temp.setInches(fInches+dd.fInches); iFeet++; //ERROR!! return temp; /*End of Distlib.cpp*/ /*Header file containing the definition of the Distance class*/ class Distance { int iFeet; float fInches; public: void setFeet(int); int getFeet() const; //constant function void setInches(float); float getInches() const; //constant func Distance add(Distance) const; //constant fun }; /*End of Distance.h*/

124 Contd… For constant member functions, the this pointer becomes ‘a constant pointer to a constant’ instead of only ‘a constant pointer’. For example, the this pointer is of type const Distance * const.

125 Mutable Data Members A mutable data member is never constant. It can be modified inside constant functions also. Prefixing the declaration of a data member with the keyword mutable makes it mutable. /*Beginning of mutable.h*/ class A { int x; //non-mutable data member mutable int y; //mutable data member public: void abc() const //a constant member function x++; //ERROR: cannot modify a non-constant data member in a constant member function y++; //OK: can modify a mutable data member in a constant member function } void def() //a non-constant member function x++; //OK: can modify a non-constant data member in a non-constant member function y++; //OK: can modify a mutable data member in a non-constant member function }; /*End of mutable.h*/

126 Friends A class can have global non-member functions and member functions of other classes as friends. Such functions can directly access the private data members of objects of the class. Friend non-member functions: A friend function is a non-member function that has special rights to access private data members of any object of the class of whom it is a friend. A friend function is prototyped within the definition of the class of which it is intended to be a friend. The prototype is prefixed with the keyword friend. Since it is a non-member function, it is defined without using the scope resolution operator.

127 Example /*Beginning of friend.cpp*/ class A { int x; public: friend void abc(A&); //prototype of the friend function }; void abc(A& AObj) //definition of the friend function AObj.x++; //accessing private members of the object } void main() A A1; abc(A1); /*End of friend.cpp*/

128 Contd… A few points about the friend functions that we must keep in mind are as follows: 1) friend keyword should appear in the prototype only and not in the definition. 2) Since it is a non-member function of the class of which it is a friend, it can be prototyped in either the private or the public section of the class. 3) A friend function takes one extra parameter as compared to a member function that performs the same task. This is because it cannot be called with respect to any object. Instead, the object itself appears as an explicit parameter in the function call. 4) We need not and should not use the scope resolution operator while defining a friend function. There are situations where a function that needs to access the private data members of the objects of a class cannot be called with respect to an object of the class. In such situations, the function must be declared as a friend.

129 Friend classes A class can be a friend of another class.
Member functions of a friend class can access private data members of objects of the class of which it is a friend. If class B is to be made a friend of class A, then the statement friend class B; should be written within the definition of class A. class A { friend class B; //declaring B as a friend of A /* rest of the class A */ }; It does not matter whether the statement declaring class B as a friend is mentioned within the private or the public section of class A. Now, member functions of class B can access the private data members of objects of class A

130 Example /*Beginning of friendClass.cpp*/ class B; //forward declaration… necessary because //definition of class B is after the statement //that declares class B a friend of class A. class A { int x; public: void setx(const int=0); int getx( ) const; friend class B; //declaring B as a friend of A }; class B A * APtr; void Map(A * const); void test_friend(const int); void B::Map(A * const p) APtr = p; } void B::test_friend(const int i) APtr->x=i; //accessing the private data member /*End of friendClass.cpp*/ As we can see, member functions of class B are able to access private data member of objects of the class A although they are not member functions of class A.

131 Contd… Friendship is not transitive. class B; class C;
/*Beginning of friendTran.cpp*/ class A { friend class B; int a; }; class B friend class C; class C void f(A * p) p->a++; //error: C is not a friend of A //despite being a friend of a friend } /*End of friendTran.cpp*/

132 Friend member functions
How can we make some specific member functions of one class friendly to another class? For making only B::test_friend() function a friend of class A, replace the line friend class B; in the declaration of the class A with the line friend void B::test_friend(); The modified definition of the class A is class A { /* rest of the class A */ }; However, in order to compile this code successfully, the compiler should first see the definition of the class B. Otherwise, it does not know that test_friend() is a member function of the class B.

133 Contd… However, a pointer of type A * is a private data member of class B. So, the compiler should also know that there is a class A before it compiles the definition of class B. This problem of circular dependence is solved by forward declaration. class A; class B { A * APtr; public: void Map(const A * const); void test_friend(const int=0); }; class A int x; friend void B::test_friend(const int=0); /*End of friendMemFunc.h*/

134 Contd… Another problem arises if we try to define the B::test_friend() function as an inline function by defining it within class B itself. class B { /* rest of the class B */ public: void test_friend(const int p) APtr->x=p; //will not compile } }; But how will the code inside B::test_friend() function compile? The compiler will not know that there is a data member ‘x’ inside the definition of class A. For overcoming this problem, merely prototype B::test_friend() function within class B; define it as inline after the definition of class A in the header file itself. The

135 Contd… /*Beginning of friendMemFuncInline.h*/ class A; class B { A * APtr; public: void Map(const A * const); void test_friend(const int=0); }; class A int x; friend void B::test_friend(const int=0); inline void B::test_friend(const int p) APtr->x=p; } /*End of friendMemFuncInline.h*/

136 Friends as bridges Friend functions can be used as bridges between two classes. Suppose there are two unrelated classes whose private data members need a simultaneous update through a common function. This function should be declared as a friend to both the classes. class B; //forward declaration class A { /* rest of the class A */ friend void ab(const A&, const B&); }; class B rest of the class B

137 Static Members Static member data: Static data members hold global data that is common to all objects of the class. Examples of such global data are 1) count of objects currently present, 2) common data accessed by all objects, etc. Let us consider class Account. We want all objects of this class to calculate interest at the rate of say 4.5%. Therefore, this data should be globally available to all objects of this class. This data cannot and should not be a member of the objects themselves. Otherwise, multiple copies of this data will be embedded within the objects taking up unnecessary space. Same value would have to be maintained for this data in all objects. This is very difficult. Thus, this data cannot be stored in a member variable of class Account. At the same time, this data should not be stored in a global variable. Then the data is liable to be changed by even non-member functions. It will also potentially lead to name conflicts. OHHHHHHHH…………………… Now how this conflict can be resolved??

138 Contd… Storing the data in a static variable of the class resolves this conflict. Static data members are members of the class and not of any object of the class, that is, they are not contained inside any object. We prefix the declaration of a variable within the class definition with the keyword static to make it a static data member of the class. A statement declaring a static data member inside a class will obviously not cause any memory to get allocated for it. Moreover, memory for a static data member will not get allocated when objects of the class are declared. This is because a static data member is not a member of any object. Therefore, we must not forget to write the statement to define (allocate memory for) a static member variable. /*Beginning of Account.h*/ class Account { static float interest_rate; //a static data member /* rest of the class Account */ }; /*End of Account.h*/

139 Contd… Explicitly defining a static data member outside the class is necessary. Otherwise, the linker produces an error. The following statement allocates memory for interest_rate member of class Account. float Account::interest_rate; The above statement initializes interest_rate to zero. If some other initial value (say 4.5) is desired instead, the statement should be rewritten as follows. float Account::interest_rate=4.5; Static data members should be defined in the implementation files only. The header file is included in both the implementation file and the driver program. Making static data members private prevents any change from non-member functions as only member functions can change the values of static data members. Introducing static data members does not increase the size of objects of the class. Static data members are not contained within objects. There is only one copy of the static data member in the memory.

140 Example Static data members can be of any type.
/*Beginning of staticSize.cpp*/ #include<iostream.h> class A { int x; char y; float z; static float s; }; float A::s=1.1; void main() cout<<sizeof(A)<<endl; } /*End of staticSize.cpp*/ /*Beginning of Account.h*/ class Account { static float interest_rate; static char name[30]; /* rest of the class Account */ }; /*End of Account.h*/ /*Beginning of Account.cpp*/ #include“Account.h” float A::interest_rate=4.5; char A::name[30]=“The Rich and Poor Bank”; definitions of the rest of the functions of class Account /*End of Account.cpp*/ Output 9

141 Example We must notice that the static data member that has been initialized inside the class must be still defined outside the class to allocate memory for it. Once the initial value has been supplied within the class, the static data member must not be re-initialized when it is defined. the variable nameLength is referred to directly without the class name and the scope resolution operator while definning the variable name. One static data member can directly refer to another without using the scope resolution operator. /*Beginning of Account.h*/ class Account { static int nameLength=30; static char name[nameLength]; /* rest of the class Account */ }; /*End of Account.h*/ /*Beginning of Account.cpp*/ #include“Account.h” int A::nameLength; char A::name[nameLength]=“The Rich and Poor Bank”; definitions of the rest of the functions of class Account /*End of Account.cpp*/

142 Contd… We must notice that the static data member that has been initialized inside the class must be still defined outside the class to allocate memory for it. Non-integral static data members cannot be initialized like this. /*Beginning of Account.h*/ class Account { static char name[30]=“The Rich and Poor Bank”; //error!! /* rest of the class Account */ }; /*End of Account.h*/

143 Contd… Member functions can refer to static data members directly.
/*Beginning of Account.h*/ class Account { static float interest_rate; public: void updateBalance(); /* rest of the class Account */ }; /*End of Account.h*/ /*Beginning of Account.cpp*/ #include“Account.h” float Account::interest_rate=4.5; void Account::updateBalance() { if(end_of_year) balance+=balance*interest_rate/100; } /* definitions of the rest of the functions of class Account */ /*End of Account.cpp*/

144 Contd… The object-to-member access operator can be used to refer to the static data member of a class with respect to an object. The class name with the scope resolution operator can do this directly. f=a1.interest_rate; //a1 is an object of the class Account f=Account::interest_rate; There are some things static data members can do but non-static data members cannot. 1) A static data member can be of the same type as the class of which it is a member. class A { static A A1; //OK : static A * APtr; //OK : pointer A A2; //ERROR!! : non-static }; A static data member can appear as the default value for the formal arguments of member functions of its class.

145 Contd… class A { static int x; int y; public: void abc(int=x); //OK
void def(int=y); //ERROR!! : object required }; A static data member can be declared to be a constant. In that case, the member functions will be able to only read it but not modify its value. Static member functions : How do we create a member function that need not be called with respect to an existing object? This function’s sole purpose is to access and/or modify static data members of the class. Static member functions fulfill the above criteria. Prefixing the function prototype with the keyword static specifies it as a static member function. However, the keyword static should not reappear in the definition of the function.

146 Contd… Suppose there is a function set_interest_rate() that sets the value of the interest_rate static data member of class Account. The application programmer should be able to call this function even if no objects have been declared. As discussed previously, this function should be static. /*Beginning of Account.h*/ class Account { static float interest_rate; public: static void set_interest_rate(float); /* rest of the class Account */ }; /*End of Account.h*/ /*Beginning of Account.cpp*/ #include“Account.h” float Account::interest_rate = 4.5; void Account::set_interest_rate(float p) interest_rate=p; } definitions of the rest of the functions of class Account /*End of Account.cpp*/

147 Objects and Functions Objects can appear as local variables inside functions. They can also be passed by value or by reference to functions. /*Beginning of Distance.h*/ class Distance { public: /*function to add the invoking object with another object passed as a parameter and return the resultant object*/ Distance add(Distance); /* rest of the class Distance */ }; /*End of Distance.h*/ /*Beginning of Distance.cpp*/ #include“Distance.h” Distance Distance::add(Distance dd) { Distance temp; temp.iFeet=iFeet+dd.iFeet; temp.setInches(fInches+dd.fInches); return temp; } /* definitions of the rest of the functions of class Distance */ /*End of Distance.cpp*/ /*End of Distance.cpp*/ /*Beginning of Distmain.cpp*/ #include<iostream.h> #include“Distance.h” void main() { Distance d1,d2,d3; d1.setFeet(5); d1.setInches(7.5); d2.setFeet(3); d2.setInches(6.25); d3=d1.add(d2); cout<<d3.getFeet()<<“ ”<<d3.getInches()<<endl; } /*End of Distmain.cpp*/

148 Contd… Arrays of Objects :
They can be returned by the value or by functions. Arrays of Objects : It is possible to create array of objects. ➢ We can have arrays of variables that are of the type class. Such variables are called arrays of objects. Ex: class employee { char name[20]; float age; public: void getdata(); void putdata(); } Creating array of objects: employee manager[3]; // array of manager employee worker[75]; // array of worker. ➢ The array of manager contains three objects, manager[0], manager[1] and manager[2].

149 Contd… Accessing array of objects manager[i].getdata();
manager[i].putdata(); Storage of array of objects Name Age Manager[0] Manager[1] Manager[2]

150 Example Output Enter the feet : 1
#include“Distance.h” #include<iostream.h> #define SIZE 3 void main() { Distance dArray[SIZE]; int a; float b; for(int i=0;i<SIZE;i++) cout<<“Enter the feet : ”; cin>>a; dArray[i].setFeet(a); cout<<“Enter the inches : ”; cin>>b; dArray[i].setInches(b); } cout <<dArray[i].getFeet()<<“ ” <<dArray[i].getInches()<<endl; /*End of DistArray.cpp*/ Output Enter the feet : 1 Enter the inches : 1.1 Enter the feet : 2 Enter the inches : 2.2 Enter the feet : 3 Enter the inches : 3.3

151 Arrays inside Objects ➢An array can be declared inside a class.
➢Such an array becomes a member of all objects of the class. ➢It can be manipulated/accessed by all member functions of the class. Ex: class example { int arr[10]; } #define SIZE 3 /*A class to duplicate the behaviour of an integer array*/ class A { int iArray[SIZE]; public: void setElement(unsigned int,int); int getElement(unsigned int); }; /*function to write the value passed as second parameter at the position passed as first parameter*/ void A::setElement(unsigned int p,int v) if(p>=SIZE) return; //better to throw an exception iArray[p]=v; } /*function to read the value from the position passed as parameter*/ int A::getElement(unsigned int p) return –1; //better to throw an exception return

152 Namespaces Namespaces enable the C++ programmer to prevent pollution of the global namespace that leads to name clashes. The term ‘global namespace’ refers to the entire source code. It also includes all the directly and indirectly included header files. By default, the name of each class is visible in the entire source code, that is, in the global namespace. It leads to following problems Now, let us include both these header files in a program and see what happens if we declare an object of the class. /*Beginning of A1.h*/ class A { }; /*End of A1.h*/ /*Beginning of A2.h*/ class A //a class with an existing name /*End of A2.h*/

153 Contd…. How can this problem be overcome? How can we ensure that an application is able to use both definitions of class A simultaneously? Ans: Enclosing the two definitions of the class in separate namespaces overcomes this problem. /*Beginning of multiDef01.cpp*/ #include”A1.h” #include”A2.h” void main() { A AObj; //ERROR: Ambiguity error due to // multiple definitions of A } /*End of multiDef01.cpp*/ The global visibility of the definition of class A makes the inclusion of the two header files mutually exclusive. Consequently, this also makes use of the two definitions of class A mutually exclusive.

154 Contd… Now, the two definitions of the class are enveloped in two different namespaces. The corresponding namespace, followed by the scope resolution operator, must be prefixed to the name of the class while referring to it anywhere in the source code. Thus, the ambiguity encountered in the above listing can be overcome. /*Beginning of A1.h*/ namespace A //beginning of a namespace A1 { class A }; } //end of a namespace A1 /*End of A1.h*/ /*Beginning of A2.h*/ namespace A //beginning of a namespace A2 } //end of a namespace A2 /*End of A2.h*/ /*Beginning of using.cpp*/ #include“A1.h” #include“A2.h” void main() { using namespace A1; A AObj1; //OK: AObj1 is an object of the class defined in A1.h A2::A AObj2; //OK: AObj2 is an object of the class defined in A2.h }

155 Contd… However, we must note that the using directive brings back the global namespace pollution that the namespaces mechanism was supposed to remove in the first place! The last line in the above listing compiles only because the class name was qualified by the name of the namespace. Some namespaces have long names. Qualifying the name of a class that is enclosed within such a namespace, with the name of the namespace, is cumbersome. /*Beginning of longName01.cpp*/ namespace a_very_very_long_name { class A }; } void main() a_very_very_long_name::A A1; //cumbersome long name /*End of longName01.cpp*/

156 Contd… Assigning a suitably short alias to such a long namespace name solves the problem as illustrated Aliases provide an incidental benefit also. Suppose an alias has been used at a number of places in the source code. Changing the alias declaration so that it stands as an alias for a different namespace will make each reference of the enclosed class refer to a completely different class. /*Beginning of longName02.cpp*/ namespace a_very_very_long_name { class A }; } namespace x = a_very_very_long_name; //declaring an alias void main() x::A A1; //convenient short name /*End of longName02.cpp*/

157 Contd… Suppose an alias X refers to a namespace ‘N1’.
namespace X = N1; //declaring an alias Further, suppose that this alias has been used extensively in the source code. X::A AObj; //AObj is an object of class A that is enclosed in namespace N1. AObj.f1(); //f1() is a member function of the above class. If the declaration of alias X is modified as follows namespace X = N2; //modifying the alias then, all existing qualifications of referred class names that use X would now refer to class A that is contained in namespace ‘N2’.

158 Nested Inner Classes A class can be defined inside another class. Such a class is known as a nested class. The class that contains the nested class is known as the enclosing class. Nested classes can be defined in the private, protected, or public portions of the enclosing class. /*Beginning of nestPrivate.h*/ class A { class B /* definition of class B */ }; definition of class A /*End of nestPrivate.h*/ /*Beginning of nestPublic.h*/ class A { public: class B /* definition of class B */ }; definition of class A /*End of nestPublic.h*/

159 Contd… A nested class is created if it does not have any relevance outside its enclosing class. By defining the class as a nested class, we avoid a name collision. In Above Listings , even if there is a class B defined as a global class, its name will not clash with the nested class B. /*Beginning of nestSize.cpp*/ #include<iostream.h> class A { int x; public: class B int y; }; void main() cout<<sizeof(int)<<endl; cout<<sizeof(A)<<endl; } /*End of nestSize.cpp*/ Output 4 The size of objects of an enclosing class is not affected by the presence of nested classes.

160 Contd… Member functions of a nested class can be defined outside the definition of the enclosing class. This is done by prefixing the function name with the name of the enclosing class followed by the scope resolution operator. This, in turn, is followed by the name of the nested class followed again by the scope resolution operator. /*Beginning of nestClassDef.h*/ class A { public: class B void BTest(); //prototype only }; /* definition of class A */ /*End of nestClassDef.h*/ /*Beginning of nestClassDef.cpp*/ #include“nestClassDef.h” void A::B::BTest() { //definition of A::B::BTest() function } /* definitions of the rest of the functions of class B */ /*End of nestClassDef.cpp*/

161 Contd… A nested class may be only prototyped within its enclosing class and defined later. Again, the name of the enclosing class followed by the scope resolution operator is required. Objects of the nested class are defined outside the member functions of the enclosing class in much the same way (by using the name of the enclosing class followed by the scope resolution operator). A: :B B1; However, the above line will compile only if class B is defined within the public section of class A. Otherwise, a compile-time error will result. /*Beginning of nestClassDef.h*/ class A { class B; //prototype only }; class A::B /* definition of the class B */ /*End of nestClassDef.h*/

162 Contd… An object of the nested class can be used in any of the member functions of the enclosing class without the scope resolution operator. Moreover, an object of the nested class can be a member of the enclosing class. In either case, only the public members of the object can be accessed unless the enclosing class is a friend of the nested class. /*Beginning of nestClassObj.h*/ class A { class B public: void BTest(); //prototype only }; B B1; void ATest(); /*End of nestClassObj.h*/ /*Beginning of nestClassObj.cpp*/ #include“nestClassObj.h” void A::ATest() { B1.BTest(); B B2; B2.BTest(); } /*End of nestClassObj.cpp*/

163 Contd… Member functions of the nested class can access the non-static public members of the enclosing class through an object, a pointer, or a reference only. It can be observed that an error is produced when a direct access is made to a member of the enclosing class through a function of the nested class. #include“enclClassObj.h” void A::B::BTest(A& ARef) { ARef.ATest(); //OK } void A::B::BTest1() ATest(); //ERROR!! /*End of enclClassObj.cpp*/ /*Beginning of enclClassObj.h*/ class A { public: void ATest(); class B void BTest(A&); void BTest1( ); }; /*End of enclClassObj.h*/ }

164 Constructors and Destructors
Constructors : The constructor gets called automatically for each object that has just got created. It appears as member function of each class, whether it is defined or not. It has the same name as that of the class. It may or may not take parameters. It does not return anything (not even void). The prototype of a constructor is <class name> (<parameter list>); TYPES OF CONSTRUCTORS: Default Constructor Zero-argument Constructor Parameterized Constructors Explicit Constructors Copy Constructor

165 Contd… we want the value of data member fInches of each object of the class Distance to be between 0.0 and 12.0 at all times within the lifetime of the object. But this condition may get violated in case an object has just got created. However, introducing a suitable constructor to the class Distance can enforce this condition. The compiler embeds a call to the constructor for each object when it is created. Suppose a class A has been declared as follows: /*Beginning of A.h*/ class A { int x; public: void setx(const int=0); int getx(); }; /*End of A.h*/ /*Beginning of AMain.cpp*/ #include“A.h” void main() { A A1; //object declared … constructor called } /*End of AMain.cpp*/

166 Contd… The statement in the function main() is transformed into the following statements. A A1; //memory allocated for the object (4 bytes) A1.A( ); //constructor called implicitly by compiler The second statement above is then transformed to A(&A1); Similarly, the constructor is called for each object that is created dynamically in the heap by the new operator. A * APtr; APtr = new A; //constructor called implicitly by compiler The second statement above is transformed into the following two statements. APtr = new A; //memory allocated APtr->A( ); //constructor called implicitly by compiler The second statement above is then transformed into A(APtr);

167 Contd… The foregoing explanations make one thing very clear.
Unlike their name, constructors do not actually allocate memory for objects. They are member functions that are called for each object immediately after memory has been allocated for the object.

168 Contd… A constructor guarantees that an object created by the class will be initialized automatically.

169 Contd… Ex: create an object integer int1;
Object int1 is created, and also initializes its data members m and n to zero. There is no need to write any statement to invoke the constructor function. If a normal member function is defined for zero initialization, we would need to invoke this function for each of the objects separately. This would be very inconvenient, if there are a large number of objects.

170 Contd…

171 Contd…

172 Contd… Default Constructor Accepts no parameters.
Also called as Zero Constructor. If no such constructor is defined, then the compiler supplies a default constructor.

173 Contd… Parameterized Constructor
A constructor that takes arguments or parameters are called Parameterized constructors. We can pass the arguments to constructor function when object are created.

174 Contd… 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. By calling the constructor explicitly integer int1 = integer(10, 100); This statement creates an integer object int1 and passes the values 10 and 100 to it. By calling the constructor implicitly integer int1(10, 100); Also called as short hand method, shorter, better and easy to implement.

175 Contd…

176 Contd… Copy Constructor
Copy Constructor is used to declare and initialize an object from another object. Ex: integer I2 ( I1 ); This would define an object I2 and at the same time initialize it to the values of I1. Another form: integer I2 = I1;//it simply assigns the values of I1 to I2, member-by-memeber The process of initializing through a copy constructor is known as copy initialization. A copy constructor takes a reference to an object of the same class as itself as an argument.

177 Contd… 1. Object declarations: integer I1;
Multiple Constructors in a Class class integer { int m, n; public: integer() //Default Constructor m=0; n=0; } integer(int a, int b) //Parameterized Constructor m=a; n=b; integer(integer & i) //Copy Constructor m = i.m; n=i.n; }; - invokes default constructor and set both m and n of I1 to 0. 2. Object declarations: integer I2(20, 40); - invokes parameterized constructor and set both m and n of I2 to 20 and 40 respectively. 3. Object declarations: integer I3(I2); - invokes copy constructor which copies the values of I2 into I3.

178 Contd… The actual parameter, when specified, overrides the default value

179 Contd… Default Constructor Default Argument Constructor A :: A()
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)

180 Zero-argument Constructor
We can and should define our own constructors if the need arises. If we do so, the compiler does not define the constructor. However, it still embeds implicit calls to the constructor as before. The constructor is a non-static member function. It is called for an object. It, therefore, takes the this pointer as a leading formal argument just like other non-static member functions. Correspondingly, the address of the invoking object is passed as a leading parameter to the constructor call. This means that the members of the invoking object can be accessed from within the definition of the constructor.

181 Example class A { int x; public: A(); //our own constructor
void setx(const int=0); int getx(); }; /*End of A.h*/ /*Beginning of A.cpp*/ #include”A.h” #include<iostream.h> A::A() //our own constructor { cout<<”Constructor of class A called\n”; } /* definitions of the rest of the functions of class A */ /*End of A.cpp*/ /*Beginning of AMain.cpp*/ #include“A.h” void main() A A1; cout<<”End of program\n”; /*End of AMain

182 Destructors Used to destroy the objects that have been created by a constructor. The destructor is a member function whose name is the same as the class name but is preceded by a tilde( ~). Destructor of class integer can be defined as; ~integer( ) { } Destructor never takes any argument nor does it return any value. It will be invoked implicitly by the compiler upon exit from the program to clean up storage that is no longer accessible. (No need to call it explicitly) Destructors releases memory space for future use. Destructors destroy the objects in the reverse order of creation.

183 Contd… Whenever new is used to allocate memory in the constructors, we should use delete to free that memory. This is required because when the pointers to objects go out of scope, a destructor is not called implicitly. Constructors.cpp Destructors.cpp DestructoroutofScope.cpp beforeDestructor.cpp CopyConstructors.cpp OverloadedConstructors.cpp ParameterizedConstructors.cpp

184 Contd… Ex: void main( ) { A A1; } //A1 goes out of scope here
‘A1’ goes out of scope just before the main() function terminates. At this point, the compiler embeds a call to the destructor for ‘A1’. It embeds the following statement. A1.~A(); //destructor called • The destructor will also be called for an object that has been dynamically created in the heap just before the delete operator is applied on the pointer pointing at it. A * APtr; APtr = new A; //object created … constructor called delete APtr; //object destroyed … destructor called The last statement is transformed into APtr->~A( ); //destructor called for *APtr delete APtr; //memory for *APtr released

185 Contd… The destructor does not ‘destroy’ or deallocate memory that an object occupies. It is merely a member function that is called for each object just before the object goes out of scope (gets destroyed). Before class A { public: }; void main( ) A A1; } After class A { Public: ~A(); //prototype inserted implicitly by compiler }; A::~A( ) //empty definition inserted implicitly by compiler } void main( ) A A1; A1.~A( );

186 Contd… /*Beginning of AMain.cpp*/ #include“A.h”
/*Beginning of A.h*/ class A { int x; public: A( ); void setx(const int=0); int getx(); ~A( ); //our own destructor }; /*End of A.h*/ /*Beginning of A.cpp*/ #include“A.h” #include<iostream.h> A::A() cout<<“Constructor of class A called\n”; } A::~A() //our own destructor cout<<“Destructor of class A called\n”; /* definitions of the rest of the functions of class A */ /*End of A.cpp*/ /*Beginning of AMain.cpp*/ #include“A.h” #include<iostream.h> void main() { A A1; cout<<“End of program\n”; } /*End of AMain.cpp*/

187 Zero-argument Constructor Example
Output Constructor of Class A called End of rogram

188 Parameterized Constructor
Output


Download ppt "INTRODUCTION TO OBJECT ORIENTED CONCEPTS: By: Pavan D. M."

Similar presentations


Ads by Google