OOPs Lab Manual



Comments



Description

- 1- KALASALINGAM UNIVERSITY (KALASALINGAM ACADEMY OF RESEARCH AND EDUCATION) ANAND NAGAR, KRISHNANKOIL – 626190. Department of computer Science and Engineering OBJECT ORIENTED PROGRAMMING LAB (CSE285) LAB MANUAL - 2 - Table of contents S.No Topic Page No 1 2 3 4 5 6 7 8 9 10 11 Introduction 1.1 Object Oriented Programming Lab Objectives 1.2 Tools Required 1.3 Lab Plan 1.4 Instructions to faculties 1.5 Instructions to students 1.6 Method of evaluation Simple C++ Programs Programs using functions Programs using classes Function overloading Operator overloading Inheritance Polymorphism and Virtual functions File Handling and I/O Manipulation Templates – Function and class templates Exception handling Appendix A – C++ reserved words Appendix B – C++ Programming Guidelines Appendix C – Sample Programs Reference 3 3 4 4 5 6 7 9 12 16 24 28 31 37 46 58 64 70 71 83 88 - 3 - OBJECT ORIENTED PROGRAMMING LAB CSE285 LAB MANUAL 1. Introduction Programming language which serves as the intelligent of any computer systems has evolved tremendously since it was first developed. Currently, in most electronic devices ranging from mobile handset to washing machine even to cars have computer embedded system and thus requires some form of programming language to govern the operation of those devices. Object-oriented programming (OOP) is a programming paradigm that uses abstraction to create models based on the real world. It utilizes several techniques from previously established paradigms, including modularity, polymorphism and encapsulation. Even though it originated in 1960’s, OOP was not commonly used in mainstream software application development until the 1990s. Today, many popular programming languages such as Java, JavaScript, C# , C++, Python support OOP. OOP may be seen as a collection of cooperating objects, as opposed to a traditional view in which a program may be seen as a collection of functions, or simple as a list of instructions to the computer. In OOP, each object is capable of receiving messages, processing data, and sending messages to other objects. Each object can be viewed as an independent little machine with a distinct role or responsibility. OOP is intended to promote greater flexibility and maintainability in programming, and is widely popular in large-scale software engineering. By virtue of its strong emphasis on modularity, object oriented code is intended to be simpler to develop and easier to understand later on, lending itself to more direct analysis, coding, and understanding of complex situations and procedures than less modular programming methods. C++ is one of the high-level language that is developed by Bjarne Stroustrup (http://www.research.att.com/~bs/homepage.html), of which is - 4 - actually C is a subset of C++. It is developed on basis of enabling object-oriented programming, where the students will learn and apply its concept in this subject. 1.1 Object Oriented Programming Lab Objectives To provide the student with the fundamental knowledge and skills to become a proficient C++ programmer. To learn to transpose the physical problem domain into a hierarchy of objects. To develop ability of using OOP to solve simple engineering problems To work with advanced futures of C++ (templates, exception handling). 1.2 Tools Required Hardware Requirement Pentium IV 512 MB RAM 20 GB Hard disk drive Software Requirement Windows 9x or above Turbo C++ compiler Microsoft Visual C++ 6.0 1.3 Lab Plan Week # Lab Content Software Week 1 Simple C++ programs Turbo C++ / VC++ Week 2 Programs Using Functions Turbo C++ / VC++ Week 3 & 4 Programs using Classes ( Constructor, destructor, Friend Functions etc) Turbo C++ / VC++ Week 5 Function Overloading Turbo C++ / VC++ Week 6 Operator Overloading Turbo C++ / VC++ Week 7 Simple and Multiple Inheritance Turbo C++ / VC++ Week 8 Multilevel and hybrid Inheritance Turbo C++ / VC++ - 5 - Week 9 Model Lab Exam # 1 Turbo C++ / VC++ Week 10 Virtual Functions Turbo C++ / VC++ Week 11 Polymorphism Turbo C++ / VC++ Week1 2 File Handling and I/O Manipulation Turbo C++ / VC++ Week 13 Templates – Function Templates and Class Templates VC++ Week1 4 Exception Handling VC++ Week 15 Model Lab Exam # 2 Turbo C++ / VC++ 1.4 Instructions to Faculties Learning Overview: To develop better understanding of importance of the subject. To know related skills to be developed such as Intellectual skills. Know your Laboratory Work: To understand the layout of laboratory, specifications of Equipment / Instruments / Software, procedure, working in groups, planning time etc. Also to know total amount of work to be done in the laboratory. Faculties shall ensure that required equipments are in working condition before start of experiment, also keep operating instruction manual available. Explain prior concepts to the students before starting of each experiment. Involve student’s activity at the time of conduct of each experiment. List of questions is given at the end of each experiment. Faculties shall instruct the students to attempt all questions given at the end of each experiment / exercise. Faculties shall ensure that each student writes the answers to the allotted questions in the laboratory manual after performance is over. Faculties shall assess the performance of students continuously. Faculties should ensure that the respective skills and competencies are developed in the students after the completion of the practical exercise. - 6 - Faculties are expected to share the skills and competencies to be developed in the students. Faculties may provide additional knowledge and skills to the students even though not covered in the manual but are expected from the students by the industries. Faculties may suggest the students to refer additional related literature of the Technical papers / Reference books / Seminar proceedings, etc. During assessment faculties are expected to ask questions to the students to tap their achievements regarding related knowledge and skills so that students can prepare while submitting record of the practical. Faculties should enlist the skills to be developed in the students that are expected by the industry. 1.5 Instructions to Students Students shall read the points given below for understanding the theoretical concepts and practical applications. Listen carefully to the lecture given by teacher about importance of subject, curriculum philosophy, learning structure, skills to be developed and procedure method of continuous assessment, tentative plan of work in laboratory and total amount of work to be done in a semester. Read the write up of each experiment to be performed, a day in advance. Organize the work in the group and make a record of all programs, algorithms. Understand the purpose of experiment and its practical implications. Write the answers of the viva questions allotted by the teacher during practical hours if possible or afterwards, but immediately. Student should not hesitate to ask any difficulty faced during conduct of practical / exercise. The student shall study all the questions given in the laboratory manual and practice to write the answers to these questions. - 7 - Student shall develop maintenance skills as expected by the industries. Student should develop the habit of pocket discussion / group discussion related to the experiments / exercises so that exchanges of knowledge / skills could take place. Student shall attempt to develop related hands - on - skills and gain confidence. Student shall focus on development of skills rather than theoretical or codified knowledge. Student shall develop the habit of evolving more ideas, innovations, skills etc. those included in the scope of the manual. Student shall refer technical magazines, proceedings of the Seminars, refer websites related to the scope of the subjects and update his knowledge and skills. Student should develop the habit of not to depend totally on teachers as well as their classmates but to develop self learning techniques. Student should develop the habit to react with the teacher without hesitation with respect to the academics involved. Student should develop habit to submit the practical, exercise continuously and progressively on the scheduled dates and should get the assessment done. Student should be well prepared while submitting the write up of the exercise. This will develop the continuity of the studies and he will not be over loaded at the end of the term. For loading C++, process is same as of C. While saving give extension as .cpp. 1.6 Method of Evaluation For each Exercise (Out of 10 Marks) 1. Algorithm - 2 Marks 2. Program - 4 marks - 8 - 3. Output - 2 Marks 4. Answers to Viva Questions - 2 Marks For Model / End Semester Practical Examination Each student will be given two programs for lab examination. 1. Algorithm - 10 (5 for each) 2. Program - 40 (20 for each) 3. Output - 40 (20 for each) 4. Viva - 10 _______ Total Marks 100 _______ End Evaluation 1. Model Practical – I - 20 Marks 2. Model Practical – II - 20 Marks 3. Record and Observation Maintenance - 10 Marks 4. End semester Practical Examination - 50 Marks ---------------- Total Marks 100 ---------------- - 9 - 2. Simple C++ Programs Aim To let the student experience coding, compiling and debugging some simple C++ programs. To get familiar in C++ form of input and output. To get familiar in writing simple C++ programs using looping statements, structures, arrays and preprocessors. Instructions 1. Each student should do a minimum of 4 experiments by using looping statements, arrays, structures and preprocessor statements. 2. Faculties can suggest their own programs also to the students. List of Exercises 1. An electricity board charges the following rates to domestic users to discourage large conceptions of energy. First 100 units Rs 1.50 p/unit From 100 to 200 units Rs 1.80 p/unit Beyond 200 Rs 2.50 p/unit All users are charged a minimum of Rs 50/-. If the total amount is more than 300 then an additional surcharge of 15% of the calculated amount is added. Write a c++ program to read the name of an user, number of units consumed and print out the Electricity bill in a neat format. 2. Create a structure book with relevant information for maintaining a book. Create an array of structure to hold a minimum of 5 book’s details. Also print all the books details in a table format. 3. Write C++ programs that produce following outputs. i) A A B A B C A B C D - 10 - ii) A B C D E A B C D A B C A B A 4. Write a C++ program to find all prime numbers between two given numbers. 5. Write a C++ program that asks to enter any number and then prints the multiplication table of that number from 1 to 10. 6. Write a C++ program to enter a matrix of 3*3 and check whether it is an identity matrix. 7. Write a C++ program to find the transpose of a given 3*3 matrix. 8. Write a program to evaluate the following functions to 0.0001% accuracy for n terms.. i) sin (x) = x – (x 3 / 3!) + (x 5 / 5!) – (x 7 / 7!) +……. ii) SUM = 1 + (1/2) 2 + (1/3) 3 + (¼) 4 +….. 9. Write a c++ program to find the cube of a square using preprocessor statements. Viva Questions 1. What is the basic difference between C and C++? 2. What are all the differences between C structure and C++ structure? 3. Name the C++ input and output statements, 4. How does a main ( ) function in C++ differ from main ( ) in C? 5. What is the purpose of a # include statement? 6. What is the need for the directive # include<iostream.h> and # include<conio.h>? 7. In C++, a variable can be declare anywhere in the scope. What is the significance of this feature? 8. What is meant by dynamic initialization of a variable? 9. Why an array is called a derived data type? - 11 - 10. What are the applications of void data type in C++? 11. What are the two types of comment styles in C++? 12. What is the difference between using a break and using continue in a looping statement? Learning Outcome At the end of this experiment the students will Get familiar with basic C++ program format. Know the input and output format of C++ language. Have a good idea of using looping statements Create, execute, and test C++ programs using calculations and decision statements, loops and arrays. - 12 - 3. Programs Using Functions Aim To make the students to get familiar in problem decomposition by using functions in C++ language. To learn various parameter passing techniques like call by value, call by address, call by reference to functions. To know how to use inline functions, default arguments and their significance in C++ programming Theory Inline function It is defined as a function definition such that each call to the function is in effect, replaced by the statements that define the function. It is expanded in line when it is invoked. The general form is Situations where inline expansion cannot work. • For functions returning values, if a loop, a switch, or a goto exists. • For functions not returning values, if a return statement exists. • If functions contain static variables. • If inline functions are recursive. Default argument Default arguments assign a default value to the parameter, which does not have matching argument in the function call. Default values are specified when the function is declared. Eg : float amount(float principle,int period, float rate=0.15) inline function-header { function body } - 13 - Function call is Value=amount(5000,7); Here it takes principle=5000& period=7 And default value for rate=0.15 Value=amount(5000,7,0.34) Passes an explicit value 0f 0.34 to rate We must add default value from right to left Static data member Static variable are normally used to maintain values common to the entire class. They are called as class variable because they are associated with the class itself rather than with any class object Features: It is initialized to zero when the first object is created. No other initialization is permitted Only one copy of it is created for the entire class and is shared by all the objects It is only visible within the class, but its life time is the entire class Type and scope of each static member variable must be defined outside the class It is stored separately rather than along with objects Eg: static int count//count is initialized to zero when an object is created. int classname::count;//definition of static data member Static member function A member function that is declared as static has the following properties A static function can have access to only other static data member declared in the same class A static member function can be called only by using the classname as follows classname ::function_name; - 14 - Const objects and const member functions We can create constant object by using const keyword before object declaration. Eg: const integer i(m,n); If a member function does not alter any data in the class, then we may declare it as const member function as void mul(int ,int) const; It const object can call const member functions. List of Exercises 1. Write a C++ program to input and output data for finding area of rectangle using functions. 2. Write a C++ program using functions to get and print a 3*3 matrix. 3. Write a C++ program to swap two integer values using functions with call by value, call by reference and call by pointers techniques. 4. Write a C++ program to find and print the volume of a cube using inline functions. 5. Write a C++ program using inline functions to find and print the maximum of three numbers. 6. Write a C++ program using default arguments to find the simple interest using a function by pasting amount, time and rate of interest. The default value for time is 1 year and that of rate of interest is 12%. 7. Write a C++ program using function to raise a number m (double) to a power n (int). Use a default value of 2 for n to make the function to calculate squares when this argument is omitted. 8. Write a C++ program to perform the following arithmetic operations of a complex number using a structure. a. Addition of two complex numbers b. Multiplication of two complex numbers 9. Write a C++ program with a structure to store the student’s details like name, roll no, height and weight. Use function and array of structure to get the details - 15 - of 5 students. Also include a function to sort them in an ascending order using the field height. Print the results in a neat format. Viva Questions: 1. What is meant by function prototyping / function declaration and function definition? 2. List out the advantages of using functions in C++. 3. What is inline function? 4. What are all the advantages of inline function? 5. What are all the differences between preprocessor statements and inline functions? 6. When inline functions should not be used? 7. What is reference variable? 8. What are all the uses of reference variable? 9. Write the differences between reference variable and pointer variable? 10. What are default arguments? 11. Mention the uses of default arguments. 12. Write the rules to use default arguments in a c++ program. Learning Outcome At the end of this experiment the students will know how to use functions and inline functions in programs come to know various parameter passing techniques learn how to pass arrays, structures to functions learn the way of using default arguments - 16 - 4. Program using Classes Aim To enhance the understanding of students about the underlying concepts of classes To demonstrate the approach to build classes and create object To learn the usage of constructors and destructors in classes Theory A class in C++ can be viewed as a customized ‘struct’ that encapsulates data and function as well. When we encapsulate data and function in one entity, most of the time, the function would not have to take trouble to ask for some data to be included in its argument list, but will still need to if it is required. Objects are basic run-time entities in an object-oriented system. They may represent a person, a place, a bank account, a table of data or any item that the program has to handle. Each object has the data and code to manipulate the data and theses objects interact with each other. 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 has been defined, we can create any number of objects belonging to the classes. Classes are user-defined data types and behave like built-in types of the programming language Format of a class definition: class your_class_name { private : // access specifier data members; member_functions(); public: data members; member_functions(); } ; - 17 - The properties or attributes of an object can be represented as data members in a class and its behaviors can be represented as member functions. The secret properties and behaviors can be kept in private section which can not be seen by remaining part of program. Whereas, the external properties and behaviors can be kept in the public function through which other part of the program will communicate with. Member functions can be defined in two ways Outside the class definition Member function can be defined outside the class by using scope resolution operator: General format: Return type class_name::function-name(arguments list) { //function body } Inside the class definition This method of defining member function is to replace the function declaration by the actual function definition inside the class. It is treated as inline function. Eg: class item { private: int a,b ; public : void getdata(int x,int y) { a=x; b=y; } } ; - 18 - Once the class has been declared, we can create objects which are variables of that type by using the classname as follows Eg : classname x; //memory for x is created Then the public members of the class can be accessed as follows: object-name . function-name(actual arguments); eg : x . getdata(100,75.5); 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 same as class name. The constructor is invoked whenever an object of its associated class is created. It is called constructor because it constructs the values of data members of the class Eg: Class integer { int i; public: integer( ) }//constructor { i = 10; }       }; The constructors are of three types • Default Constructor • Parameterized Constructor • Copy Constructor Default Constructor The constructor with no arguments is called default constructor. This will be automatically created if not specified in the program. The statement integer a; invokes the default constructor. Parameterized constructor A constructor with arguments is called parameterized constructor. Normally - 19 - these arguments will contain the initial values for data members. Copy constructor A copy constructor is used to declare and initialize an object from another object. It takes a reference to an object of the same class as an argument Eg; class integer { int m,n; public: integer( ); integer(int x,int y) // parameterized constructor { m=x;n=y; } integer(const integer &i) { m = i.m; m = i.n } ……. } ; integer::integer( )//default constructor { m=0;n=0; } Invoking constructors integer a; //calls default constructor To invoke parameterized constructor we must pass the initial values as arguments to the constructor function when an object is declared. This is done in two ways 1.By calling the constructor explicitly eg: integer int1=integer(10,10); 2.By calling the constructor implicitly eg: integer int1(10,10); To call copy constructor also we have two ways: - 20 - 1. integer i2(i1); 2. integer i2 = i1; Both the forms define the object i2 as well as time initialize it to the values of i1. Dynamic constructor Allocation of memory to data members of objects at time of their construction is known as dynamic constructor. The memory is allocated with the help of the NEW operator. The dynamic constructor can take any form of the above constructor. Eg: class string { char *name; int length; public: string( char str[10]) { length=strlen(str); name=new char[length +1]; strcpy(str, name); } } ; void main( ) { string name1(“Louis”); name3(Lagrange); } Destructor It is used to destroy the objects that have been created by constructor. Destructor name is same as class name preceded by tilde symbol(~) Eg; ~integer() { } A destructor never takes any arguments nor it does return any value. The compiler upon exit from the program will invoke it. Whenever new operator is - 21 - used to allocate memory in the constructor, we should use delete operator to free that memory. Friend functions A function that has access to the private member of the class but is not itself a member of the class is called friend functions. The general form is friend data_type function_name( ); (inside the class) Friend function is preceded by the keyword ‘friend’. Properties of friend functions. Friend function is not in the scope of the class to which it has been declared as friend. Hence it cannot be called using the object of that class. Usually it has objects as arguments. It can be declared either in the public or private part of a class. It cannot access member names directly. It has to use an object name and dot membership operator with each member name. eg: ( A . x ) List of Exercises 1. Create a class called Employee that includes three pieces of information as instance variables – a first name (type String), a last name (type String) and a monthly salary (double). Create a constructor in above class to initialize the three instance variables. Provide a get method for each instance variable. Create two employee objects and display each object’s yearly salary using display function. Give each employee a 10% raise using raise_salary function and display each Employee’s yearly salary again. 2. Create a class called time that has separate int member data for hours, minutes, and second. One constructor should initialize this data to 0, and another should initialize it to fixed values. A member function should display it, in 11:59:59 format. The final member function should add two objects of type time passed as arguments. A main ( ) program should create two initialized time objects, and - 22 - one that isn’t initialized. Then it should add the two initialized values together, leaving the result in the third time variable. Finally it should display the value of this third variable. 3. Define a class to represent a bank account. Include the following members. Data Members: Name of depositor, Account number, Type of Account, Balance amount in the account Member functions : To assign initial values, To deposit an amount, To withdraw an amount after checking the balance, To display name and balance. 4. Create a class complex with real and imaginary as data members. Also include member functions to get the values for a complex number, to add two complex number, to multiply two complex numbers, to print the complex number in a+ib format. 5. Create a class complex with real and imaginary as data members. Also include member functions to get the values for a complex number and to print the complex number in a+ib format. Also include friend functions to add two complex numbers and multiply two complex numbers. 6. Write a C++ program to implement the stack data structure using classes. 7. Define a class String that could work as a user-defined string type. Include constructors that will enable you to create an uninitialized string String S1; (string with length 0) and also to initialize an object with a string constant at the time of creation like String S2(Well done); . Include a function that adds two string to make a third string.(note that the statement s2=s1; will be perfectly reasonable expression to copy one string to another. (Use new and delete operators). Write a complete program to test your class to see that it does the following tasks: (a) Creates uninitialized string objects (b) Creates objects with string constants. 8. Write a C++ program to count the number of objects created and destroyed for a class using stating data members and static member functions. - 23 - 9. Write a c++ program with a class to represent Vector. Include necessary member functions to i) to get a vector ii) to add two vectors using friend function iii) to display a vector in the form (10,20, 30) 10. Write a C++ program with a class “Pixel” to represent a Cartesian coordinate system. Also include member functions to get, print and to move (both coordinates by +10) using this pointer. 11. Write a C++ program to depict the concept of friend class in C++. Viva Questions 1. What is the basic difference between class and structure? 2. What is the basic difference between private and protected? 3. What is constructor? What is its role? How does constructor differ from normal function? 4. What is data hiding? What is encapsulation? 5. What is the difference between writing the body of the function in side the class and outside the class? 6. What is this pointer? Write its uses. 7. What are friend functions and friend classes? 8. State the uses of static members and constant members. 9. Write the various access types of class members. 10. Write the need for destructor. Learning Outcome At the end of this experiment the students will be able to solve any real world problem with concept of classes learn the usage of constructors and destructors Know the ways of using static members, constant members and friend functions. - 24 - 5. Function Overloading Aim To understand the fundamentals of function overloading Theory Function overloading is a feature of C++ that allows us to create multiple functions with the same name, so long as they have different number and different type of parameters. Consider the following functions: int Add(int nX, int nY) { return nX + nY; } double Add(double dX, double dY) { return dX + dY; } We now have two version of Add( ): Function Call int Add(int nX, int nY); // integer version double Add(double dX, double dY); // floating point version Which version of Add() gets called depends on the arguments used in the call — if we provide two ints, C++ will know we mean to call Add(int, int). If we provide two floating point numbers, C++ will know we mean to call Add(double, double). In fact, we can define as many overloaded Add() functions as we want, so long as each Add() function has unique parameters. Consequently, it’s also possible to define Add() functions with a differing number of parameters: int Add(int nX, int nY, int nZ) { return nX + nY + nZ; } Even though this Add() function has 3 parameters instead of 2, because the parameters are different than any other version of Add(), this is valid. - 25 - Note :The function’s return type is NOT considered when overloading functions. Making a call to an overloaded function results in one of three possible outcomes: 1) A match is found. The call is resolved to a particular overloaded function. 2) No match is found. The arguments can not be matched to any overloaded function. 3) An ambiguous match is found. The arguments matched more than one overloaded function. When an overloaded function is called, C++ goes through the following process to determine which version of the function will be called: 1) First, C++ tries to find an exact match. This is the case where the actual argument exactly matches the parameter type of one of the overloaded functions. For example: 2) If no exact match is found, C++ tries to find a match through promotion. In the lesson on type conversion and casting, we covered how certain types can be automatically promoted via internal type conversion to other types. To summarize, 3) If no promotion is found, C++ tries to find a match through standard conversion. Standard conversions include: 4) Finally, C++ tries to find a match through user-defined conversion. Ambiguous matches If every overloaded function has to have unique parameters, how is it possible that a call could result in more than one match? Because all standard conversions are considered equal, and all user-defined conversions are considered equal, if a function call matches multiple candidates via standard conversion or user-defined conversion, an ambiguous match will result. For example: void Print(unsigned int nValue); void Print(float fValue); - 26 - Calls Print('a'); Print(0); Print(3.14159); In the case of Print('a'), C++ can not find an exact match. It tries promoting ‘a’ to an int, but there is no Print(int) either. Using a standard conversion, it can convert ‘a’ to both an unsigned int and a floating point value. Because all standard conversions are considered equal, this is an ambiguous match. Print(0) is similar. 0 is an int, and there is no Print(int). It matches both calls via standard conversion. Print(3.14159) might be a little surprising, as most programmers would assume it matches Print(float). But remember that all literal floating point values are doubles unless they have the ‘f’ suffix. 3.14159 is a double, and there is no Print(double). Consequently, it matches both calls via standard conversion. Ambiguous matches are considered a compile-time error. Consequently, an ambiguous match needs to be disambiguated before your program will compile. There are two ways to resolve ambiguous matches: 1) Often, the best way is simply to define a new overloaded function that takes parameters of exactly the type you are trying to call the function with. Then C++ will be able to find an exact match for the function call. 2) Alternatively, explicitly cast the ambiguous parameter(s) to the type of the function you want to call. For example, to have Print(0) call the Print(unsigned int), you would do this: Print(static_cast<unsigned int>(0)); // will call Print(unsigned int) Multiple arguments If there are multiple arguments, C++ applies the matching rules to each argument in turn. The function chosen is the one for which each argument matches at least as well as all the other functions, with at least one argument matching better than all the other functions. In other words, the function chosen must provide a better - 27 - match than all the other candidate functions for at least one parameter, and no worse for all of the other parameters. In the case that such a function is found, it is clearly and unambiguously the best choice. If no such function can be found, the call will be considered ambiguous (or a non-match). Hence function overloading can lower a programs complexity significantly while introducing very little additional risk. List of Exercises 1. Write a C++ program to find the area of a square and rectangle using function overloading. 2. Write a C++ program to find the volume of a cube, cone and a rectangle using function overloading. 3. Write a C++ program to swap two integers, floats, characters and two strings suing function overloading concept. Viva Questions 1. What are the syntactic rules governing the definition of function overloading. 2. List out the advantages of function overloading. Learning outcome At the end of this exercise, the students will be able to Understand the concept of function overloading Learn how ambiguity is handled in function overloading. - 28 - 6. Operator Overloading Aim To understand the fundamentals of operator overloading To understand the differences between overloading as member function and non-member friend function Theory Need for operator overloading If we compare the following syntaxes to perform addition of two objects a and b of a user defined class number (assume this class has a member function called add() which adds two fraction objects): 1 c=a.add(b); 2 c=a+b; Which one is easier to use, line 1 or 2? Obviously option 2 is easier. Operator overloading It is needed to make operation with user defined data type, i.e., classes, can be performed concisely. C++ has the ability to provide the operators with a special meaning for a data type. This mechanism of giving such special meanings to an operator is known as Operator overloading. It provides a flexible option for the creation of new definitions for C++ operators. The behavior of various operator on such user define data types can be specified using operator functions. Operator functions are either member functions or friend functions. The general form is return type classname :: operator op(op-arglist ) { function body } where return type is the type of value returned by specified operation. Op is the operator being overloaded. The op is preceded by a keyword operator. operator op is the function name. Limitation on operator overloading - 29 - Although C++ allows us to overload operators, it also imposes restrictions to ensure that operator overloading serves its purpose to enhance the programming language itself, without compromising the existing entity. The followings are the restrictions: Can not change the original behavior of the operator with built in data types. Can not create new operator Operators =, [], () and -> can only be defined as members of a class and not as friend or global functions The arity or number of operands for an operator may not be changed. For example, addition, +, may not be defined to take other than two arguments regardless of data type. The precedence of the operator is preserved, i.e., does not change, with overloading operators There are many ways of performing operator overloading, namely: 1. as member function 2. as non member friend function 3. as non member non friend function List of Exercises In all the following experiments, use <<, >> operator overloading functions for print and input of the members of class. 1. Write a C++ program to perform complex number addition, subtraction, multiplication using operator overloading with friend functions. 2. Write a C++ program to perform complex number addition, subtraction, multiplication using operator overloading with member functions. 3. Write a C++ program to perform matrix addition, subtraction, multiplication using operator overloading with friend functions. 4. Write a C++ program to perform matrix addition, subtraction, multiplication using operator overloading with member functions. - 30 - 5. Define a class space that represents three dimensional coordinate system. Overload unary minus operator i) Using member function ii) Using friend function. Write a C++ program to check this. 6. Create a class Integer that contains one integer data member. Overload all possible relational operators (using member functions and using friend functions) so that they operate on he objects of Integer. 7. For Integer class, overload post as well as pre increment and decrement operators. 8. Write a C++ program to overload all arithmetic assignment operator (+=, -=, *=, /=) for the complex number class using friend functions and member functions. 9. Write a C++ program to overload new and delete operators for the string class. Viva Questions 1. What is operator overloading? State the importance of operator overloading? 2. List the operators that can’t be overloaded. Give justifications. 3. What are the limitations of overloading unary increment/ decrement operator? 4. List the operators that can be overloaded with only member functions. Why? 5. Write the difference between overloading operators using friend functions and member functions. Learning Outcome At the end of this experiment, the students will Be familiar in operator overloading in C++ Learn how to overload operators using member functions and friend functions. - 31 - 7. Inheritance Aim To understand the fundamentals of inheritance To develop skills on how to use inheritance to simplify development of new classes To understand some concepts such as overridden function, protected access specifier and the sequence of constructor and destructor calls Theory Initially, OOP is proposed as a means to increase the efficiency of software developments. One of its benefits is promoting software/program reuse. Once a class is developed reliably, i.e., after went through all sorts of possible verification processes, it can be used everywhere. It can be used right away, without needing to “reinvent the wheel”. Inheritance is the process by which new classes called derived classes are created from existing classes called base classes. The derived classes have all the features of the base class and the programmer can choose to add new features specific to the newly created derived class. For example, a programmer can create a base class named fruit and define derived classes as mango, orange, banana, etc. Each of these derived classes, (mango, orange, banana, etc.) has all the features of the base class (fruit) with additional attributes or features specific to these newly created derived classes. Mango would have its own defined features, orange would have its own defined features, banana would have its own defined features, etc. Features or Advantages of Inheritance: Reusability: Inheritance helps the code to be reused in many situations. The base class is defined and once it is compiled, it need not be reworked. Using the concept of inheritance, the programmer can create as many derived classes from the base class as needed while adding specific features to each derived class as needed. - 32 - Saves Time and Effort: The above concept of reusability achieved by inheritance saves the programmer time and effort, since the main code written can be reused in various situations as needed. Increases Program Structure which results in greater reliability. Polymorphism (to be discussed in detail in later sections) Important terminologies: Base class: a class which is inherited from by other classes. E.g., class Vehicle is the base class for all other classes. Class Sedan is base class. Base class: a class which is inherited from by other classes. E.g., class Vehicle is the base class for all other classes. Class Sedan is base class for classes Honda Civic and class Nissan President. Derived class: a class which inherits from base class (es). E.g., classes Truck, Car and Bus are derived classes from base class Vehicle. Direct inheritance: inheritance relationship where the derived class inherit directly from its base class. E.g., class Car and class Vehicle have direct inheritance relationship. Indirect inheritance: inheritance relationship where the derived class inherit indirectly from its base class. Vehicle Truck Car Bus Honda Civic Sedan MPV Nissan Preside - 33 - E.g., class Honda Civic and class Car have indirect inheritance relationship. Single inheritance: a derived class inherits from a single base class. E.g., all examples in above Fig. are single inheritance Multiple inheritance: a derived class inherits from more than one base classes. Type of inheritance: private, protected, public There are three types of inheritance, namely private, protected and public inheritances. We can observe from following table that different types of inheritances have different effect on how members of the base class can be accessed from the derived classes. Base class member access specifier Type of Inheritance Public Inheritance Private Inheritance Protected Inheritance Public Public in derived class can be accessed directly by any non-static member functions, friend functions and non member functions Protected in derived class can be accessed directly by all non-static member functions and friend functions Private in derived class can be accessed directly by all non-static member functions and friend functions Protected Protected in derived class can be accessed directly by all non-static member functions and friend functions Protected in derived class can be accessed directly by all non-static member functions and friend functions Private in derived class can be accessed directly by all non-static member functions and friend functions Private Hidden in derived class. Can be accessed by non- static member function and friend functions through public or protected member functions of base class. Hidden in derived class. Can be accessed by non- static member function and friend functions through public or protected member functions of base class. Hidden in derived class. Can be accessed by non- static member function and friend functions through public or protected member functions of base class Protected Data Member Since private class members are accessible from within class scope (by member functions of the same class) and friend functions, another member access specifier called ‘protected’ is provided to enable its members accessible directly from: within the class scope friend functions - 34 - derived classes friend functions of derived classes General syntax for single inheritance: Derived_class_name : type_of_inheritance Base_class_name{ } ; General syntax for multiple inheritance: Derived_class_name : type_of_inheritance1 Base_class_name1, type_of_inheritance2 Base_class_name2,…{ } ; List of Programs 1. Imagine a publishing company that market s both book and audio-cassette versions of its work. Create a class publication that stores the title and price. From this class derive two classes book and tape; book includes one more property: page numbers and tape contains its length in minutes (float). Each of these classes must have getdata ( ) functions and putdata ( ) functions to input/output its data. Write a main function to test the book and tape classes. 2. Create a Circle class with following members. A data member that stores the radius of a circle A constructor function with an argument that initializes the radius A function that computes and returns are of a circle Create two derived classes Sector and Segment that inherit the Circle class. Both classes inherit radius and the function that returns the circle’s are from Circle. In addition to the members inherited from Circle, Sector and Segment have some specific members as follows: Sector 1. A data member that stores the control angle of a sector(in radians) 2. A constructor function with arguments that initialize radius and angle 3. A function that computes and returns the area of a sector Segment 1. A data member that stores the length of a segment in a circle 2. A constructor function with arguments that initialize radius and length - 35 - 3. A function that computes and returns the area of a segment Create the main () function to instantiate an object of each class and then call appropriate member functions to compute and return the area of a circle, sector and segment. Note : Area_of_circle = r 2 Area_of_Sector=r 2 θ/2 Area_of_segment=r 2 arccos((r-h)/r) – (r-h)(2rh-h 2 ) 1/2 Where r os the radius of a circle, θ is the central angle of a sector in radians, h is the length of a segment and arccos((r-h)/r) is in radians. 3. Create three classes Student, Test and Result classes. The student class contains student relevant information. Test class contains marks for five subjects. The result class contains Total and average of the marks obtained in five subjects. Inherit the properties of Student and Text class details in Result class through multilevel inheritance. 4. Create three classes Student, Test and Result classes. The student class contains student relevant information. Test class contains marks for five subjects. The result class contains Total and average of the marks obtained in five subjects. Inherit the properties of Student and Text class details in Result class through multiple inheritance. 5. Create three classes Employee, Boss and CEO. Employee class stores basic details like, name, employee no, department, salary. The Boss class contains bonus information and CEO class contains shares that he owns information. Include AskInfo( ) and writeInfo( ) functions in all the classes. In main create and object for CEO class and call its functions. Use scope resolution operator in CEO functions to call Employee and Boss functions. Note : CEO is a boss and boss is an employee. Viva Questions 1. What area the implications of using private, public and protected access specifiers for declaring class members for a base class. - 36 - 2. Describe the base class access control mechanism. 3. What is the firing order of the constructors under multiple and multilevel inheritance. 4. What is method overriding? 5. What are the different forms of inheritance? Give example. 6. Write the need for protected visibility specifier to a class member. 7. What are the advantages offered by inheritance? 8. Mention the members of base classes, which can’t be inherited. Learning Outcome After performing this lab, the students should be able to write c++ programs: • using the concepts of inheritance • using inheritance as a tool for code reuse • calling base-class constructors and member functions • Implementing all types if inheritances. - 37 - 8. Polymorphism & Virtual Functions Aim To learn the difference between inheritance and polymorphism To understand the mechanism of polymorphism through virtual function To understand the concept of an abstract base class Theory Polymorphism is the ability to use an operator or function in different ways. Polymorphism gives different meanings or functions to the operators or functions. Poly, referring to many, signifies the many uses of these operators and functions. A single function usage or an operator functioning in many ways can be called polymorphism. Polymorphism refers to codes, operations or objects that behave differently in different contexts. Polymorphism refers to the ability to call different functions by using only one type of function call. Polymorphism is a powerful feature of the object oriented programming language C++. A single operator + behaves differently in different contexts such as integer, float or strings referring the concept of polymorphism. The above concept leads to operator overloading. The concept of overloading is also a branch of polymorphism. When the exiting operator or function operates on new data type it is overloaded. This feature of polymorphism leads to the concept of virtual methods. Static Binding vs. Dynamic Binding Binding means the actual time when the code for a given function is attached or bound to the function call. Static Binding Dynamic Binding Actual code is attached during compile time. Actual code will be attached during run-time/execution time Implementing function overloading Implementing virtual functions - 38 - What are Virtual Functions? Virtual, as the name implies, is something that exists in effect but not in reality. The concept of virtual function is the same as a function, but it does not really exist although it appears in needed places in a program. The object- oriented programming language C++ implements the concept of virtual function as a simple member function, like all member functions of the class. The functionality of virtual functions can be over-ridden in its derived classes. The programmer must pay attention not to confuse this concept with function overloading. Function overloading is a different concept and will be explained in later sections of this tutorial. Virtual function is a mechanism to implement the concept of polymorphism (the ability to give different meanings to one function). Need for Virtual Function: The vital reason for having a virtual function is to implement a different functionality in the derived class. For example: a Make function in a class Vehicle may have to make a Vehicle with red color. A class called Four Wheeler, derived or inherited from Vehicle, may have to use a blue background and 4 tires as wheels. For this scenario, the Make function for FourWheeler should now have a different functionality from the one at the class called Vehicle. This concept is called Virtual Function. Properties of Virtual Functions: Virtual Functions are resolved during run-time or dynamic binding. Virtual functions are also simple member functions. The main difference between a non-virtual C++ member function and a virtual member function is in the way they are both resolved. A non-virtual C++ member function is resolved during compile time or static binding. Virtual Functions are resolved during run-time or dynamic binding • Dynamic Binding Property: • Virtual functions are member functions of a class. - 39 - • Virtual functions are declared with the keyword virtual, detailed in an example below. • Virtual function takes a different functionality in the derived class. Declaration of Virtual Function: Virtual functions are member functions declared with the keyword virtual. General syntax class classname //This denotes the base class of C++ virtual function { public: virtual void memberfunctionname() //This denotes the C++ virtual function { ............. ............ } } ; Referring back to the Vehicle example, the declaration of Virtual function would take the shape below: class Vehicle //This denotes the base class of C++ virtual function { public: virtual void Make() //This denotes the C++ virtual function { cout <<"Member function of Base Class Vehicle Accessed"<<endl; } } ; After the virtual function is declared, the derived class is defined. In this derived class, the new definition of the virtual function takes place. When the class FourWheeler is derived or inherited from Vehicle and defined by the virtual function in the class FourWheeler, it is written as: class Vehicle //This denotes the base class of C++ virtual function { public: virtual void Make() //This denotes the C++ virtual function { cout <<"Member function of Base Class Vehicle Accessed"<<endl; - 40 - } } ; class FourWheeler : public Vehicle { public: void Make() { cout<<"Virtual Member function of Derived class FourWheeler Accessed"<<endl; } } ; void main() { Vehicle *a, *b; a = new Vehicle(); a->Make(); b = new FourWheeler(); b->Make(); } In the above example, it is evidenced that after declaring the member functions Make() as virtual inside the base class Vehicle, class FourWheeler is derived from the base class Vehicle. In this derived class, the new implementation for virtual function Make() is placed. The programmer might be surprised to see the function call differs and the output is then printed as above. If the member function has not been declared as virtual, the base class member function is always called because linking takes place during compile time and is therefore static. In this example, the member function is declared virtual and the address is bounded only during run time, making it dynamic binding and thus the derived class member function is called. To achieve the concept of dynamic binding in C++, the compiler creates a v-table each time a virtual function is declared. This v-table contains classes and pointers to the functions from each of the objects of the derived class. This is used by the compiler whenever a virtual function is needed. C++ Pure Virtual Function and Virtual Base Class Pure Virtual Function is a Virtual function with no body. - 41 - Declaration of Pure Virtual Function: Since pure virtual function has no body, the programmer must add the notation =0 for declaration of the pure virtual function in the base class. General Syntax of Pure Virtual Function takes the form: class classname //This denotes the base class of C++ virtual function { public: virtual void virtualfunctioname() = 0 //This denotes the pure virtual function in C++ } ; To understand the declaration and usage of Pure Virtual Function, refer to this example: class Exforsys { public: virtual void example()=0; //Denotes pure virtual Function Definition } ; class Exf1:public Exforsys { public: void example() { cout<<"Welcome"; } } ; class Exf2:public Exforsys { public: void example() { cout<<"To Training"; } } ; void main() { Exforsys* arra[2]; Exf1 e1; Exf2 e2; arra[0]=&e1; - 42 - arra[1]=&e2; arra[0]->example(); arra[1]->example(); } Since the above example has no body, the pure virtual function example() is declared with notation =0 in the base class Exforsys. The two derived class named Exf1 and Exf2 are derived from the base class Exforsys. The pure virtual function example() takes up new definition. In the main function, a list of pointers is defined to the base class. Two objects named e1 and e2 are defined for derived classes Exf1 and Exf2. The address of the objects e1 and e2 are stored in the array pointers which are then used for accessing the pure virtual function example() belonging to both the derived class EXf1 and EXf2 and thus, the output is as in the above example. One must clearly understand the concept of pure virtual functions having no body in the base class and the notation =0 is independent of value assignment. The notation =0 simply indicates the Virtual function is a pure virtual function as it has no body. We may want to remove this pure virtual function from the base class as it has no body but this would result in an error. Without the declaration of the pure virtual function in the base class, accessing statements of the pure virtual function such as, arra[0]->example() and arra[1]->example() would result in an error. The pointers should point to the base class Exforsys. Special care must be taken not to remove the statement of declaration of the pure virtual function in the base class. Virtual Base Class In the following example, there are two derived classes Exf1 and Exf2 from the base class Exforsys. As shown in the above diagram, the Training class is derived from both of the derived classes Exf1 and Exf2. In this scenario, if a user has a member function in the class Training where the user wants to access - 43 - the data or member functions of the class Exforsys it would result in error if it is performed like this: class Exforsys { protected: int x; } ; class Exf1:public Exforsys { } ; class Exf2:public Exforsys { } ; class Training:public Exf1,public Exf2 { public: int example() { return x; } } ; The above program results in a compile time error as the member function example() of class Training tries to access member data x of class Exforsys. This results in an error because the derived classes Exf1 and Exf2 (derived from base class Exforsys) create copies of Exforsys called subobjects. This means that each of the subobjects have Exforsys member data and member functions and each have one copy of member data x. When the member function of the class Training tries to access member data x, confusion - 44 - arises as to which of the two copies it must access since it derived from both derived classes, resulting in a compile time error. When this occurs, Virtual base class is used. Both of the derived classes Exf1 and Exf2 are created as virtual base classes, meaning they should share a common subobject in their base class. For Example: class Exforsys { protected: int x; } ; class Exf1:virtual public Exforsys { } ; class Exf2:virtual public Exforsys { } ; class Training:public Exf1,public Exf2 { public: int example() { return x; } } ; In the above example, both Exf1 and Exf2 are created as Virtual base classes by using the keyword virtual. This enables them to share a common subobject of their base class Exforsys. This results in only one copy that the member function example() of Class Training can access the member data x. List of Programs 1. Create a base class Shape with relevant data members and member functions to get data and print the area. Create two more classes Rectangle and Triangle which inherit Shape class. Make the print data function as virtual function in base class. Write a C++ main ( ) function to check this. 2. Write a C++ program to implement virtual destructor concept. 3. Design a vehicle class that contains the following properties of motor vehicles: Fuel tank capacity, average fuel consumption per 100 km and the - 45 - distance a vehicle can travel on a full tank. The vehicle class should be designed as an abstract base class from which the Car and Truck classes are derived. The derived classes should have following member functions. • A function that contains data for a vehicle from the user • A function that computes and returns the distance a vehicle can travel on a full tank. • A function that computes and returns how many times a vehicle has to be refueled to travel a given distance. These functions should be used as pure virtual functions in the Vehicle class and refined by the derived classes. Design the main ( ) function that instantiates a pointer of Vehicle Type and , Car and Truck object respectively. The pointer should be used to invoke appropriate member functions to get and process data for car and truck. The program should output how many time each vehicle has to be refueled to travel the distance entered by the user, as well as the distance each vehicle can travel on a full tank. Viva Questions 1. Justify the need for virtual functions in C++. 2. What are pure virtual functions? How they differ from normal virtual functions? 3. What is mean by abstract class? 4. Write the role of virtual destructors. 5. What is polymorphism? 6. What id meant by compile time binding and run time binding? 7. What are the merits and demerits of using pure virtual functions? Learning Outcome At the end of this exercise, the students will know • To identify the need for virtual functions in a program • How to use the concept of abstract classes • How polymorphism work with c++. - 46 - 9. File Handling and I/O Manipulation Aim To understand and use various member functions for C++ formatted I/O. To understand and use stream manipulators for C++ formatted I/O. To open and close a file programmatically To read from a file, to process the data and to write back again to the file Theory Manipulator Manipulators are operators used in C++ for formatting output. The data is manipulated by the programmer’s choice of display. Manipulators are the most common way to control output formating. endl Manipulator: This manipulator has the same functionality as the ‘\n’ newline character. Example: cout<<”C”<<endl; cout<<”C++”; produces the output: C C++ setw Manipulator: (available in iomanip.h) This manipulator sets the minimum field width on output. The syntax is: setw(x) Here setw causes the number or string that follows it to be printed within a field of x characters wide and x is the argument set in setw manipulator. setfill Manipulator: This is used after setw manipulator. If a value does not entirely fill a field, then the character specified in the setfill argument of the manipulator is used for filling the fields. cout << setw(10) << setfill('$') << 50 << 33 << endl - 47 - Output $$$$$$$$5033 This is because the setw sets 10 width for the field and the number 50 has only 2 positions in it. So the remaining 8 positions are filled with $ symbol which is specified in the setfill argument. setprecision Manipulator: The setprecision Manipulator is used with floating point numbers. It is used to set the number of digits printed to the right of the decimal point. This may be used in two forms: fixed and scientific. These two forms are used when the keywords fixed or scientific are appropriately used before the setprecision manipulator. The keyword fixed before the setprecision manipulator prints the floating point number in fixed notation. The keyword scientific before the setprecision manipulator prints the floating point number in scientific notation. float x = 0.1; cout << fixed << setprecision(3) << x << endl; cout << sceintific << x << endl; output: 0.100 1.000000e-001 The first cout statement contains fixed notation and the setprecision contains argument 3. This means that three digits after the decimal point and in fixed notation will output the first cout statement as 0.100. The second cout produces the output in scientific notation. The default value is used since no setprecision value is provided. width(n) Same as setw(n). left Left justifies output in field width. Only useful after setw(n). - 48 - right Right justifies output in field width. Since this is the default, it is only used to override the effects of left. Only useful after setw(n). Other Manipulators Predefined Manipulator Description 1 Cout << dec, cin >> dec Makes the integer conversion base 10. 2 Cout << ends Inserts a null (0) character. Useful when dealing with strstreams. 3 cout << flush Invokes ostream::flush(). 4 Cout << hex, cin >> hex Makes the integer conversion base 16. 5 cout << oct, cin >> oct Make the integer conversion base 8. 6 cin >> ws Extracts whitespace characters (skips whitespace) until a non-whitespace character is found (which is left in istr). 7 cout << setbase(n), cin >> setbase(n) Sets the conversion base to n (0, 8, 10, 16 only). To use predefined manipulators, one must include the file iomanip.h in your program. User defined manipulators. There are two basic types of manipulator: 1. Plain manipulator--Takes an istream&, ostream&, or ios& argument, operates on the stream, and then returns its argument. 2. Parameterized manipulator--Takes an istream&, ostream&, or ios& argument, one additional argument (the parameter), operates on the stream, and then returns its stream argument. File Manipulations in C++ - 49 - C++ provides the following classes to perform output and input of characters to/from files: • ofstream: Stream class to write on files • ifstream: Stream class to read from files • fstream: Stream class to both read and write from/to files. These classes are derived directly or indirectly from the classes istream, and ostream. Open a file An open file is represented within a program by a stream object (an instantiation of one of these classes, in the previous example this was myfile) and any input or output operation performed on this stream object will be applied to the physical file associated to it. Syntax open (filename, mode); Where filename is a null-terminated character sequence of type const char * (the same type that string literals have) representing the name of the file to be opened, and mode is an optional parameter with a combination of the following flags: ios::in Open for input operations. ios::out Open for output operations. ios::binary Open in binary mode. ios::ate Set the initial position at the end of the file. If this flag is not set to any value, the initial position is the beginning of the file. ios::app All output operations are performed at the end of the file, appending the content to the current content of the file. This flag can only be used in streams open for output-only operations. ios::trunc If the file opened for output operations already existed before, its previous content is deleted and replaced by the new one. - 50 - All these flags can be combined using the bitwise operator OR (|). For example, if we want to open the file example.bin in binary mode to add data we could do it by the following call to member function open(): ofstream myfile; myfile.open ("example.bin", ios::out | ios::app | ios::binary); Each one of the open() member functions of the classes ofstream, ifstream and fstream has a default mode that is used if the file is opened without a second argument: class default mode parameter ofstream ios::out ifstream ios::in fstream ios::in | ios::out For ifstream and ofstream classes, ios::in and ios::out are automatically and respectively assumed, even if a mode that does not include them is passed as second argument to the open() member function. The default value is only applied if the function is called without specifying any value for the mode parameter. If the function is called with any value in that parameter the default mode is overridden, not combined. File streams opened in binary mode perform input and output operations independently of any format considerations. Non-binary files are known as text files, and some translations may occur due to formatting of some special characters (like newline and carriage return characters). Since the first task that is performed on a file stream object is generally to open a file, these three classes include a constructor that automatically calls the open() member function and has the exact same parameters as this member. Therefore, we could also have declared the previous myfile object and conducted the same opening operation in our previous example by writing: ofstream myfile ("example.bin", ios::out | ios::app | ios::binary); - 51 - Combining object construction and stream opening in a single statement. Both forms to open a file are valid and equivalent. To check if a file stream was successful opening a file, you can do it by calling to member is_open() with no arguments. This member function returns a bool value of true in the case that indeed the stream object is associated with an open file, or false otherwise: if (myfile.is_open()) { /* ok, proceed with output */ } Closing a file When we are finished with our input and output operations on a file we shall close it so that its resources become available again. In order to do that we have to call the stream's member function close(). This member function takes no parameters, and what it does is to flush the associated buffers and close the file: myfile.close(); Once this member function is called, the stream object can be used to open another file, and the file is available again to be opened by other processes. In case that an object is destructed while still associated with an open file, the destructor automatically calls the member function close(). Checking state flags bad( ) Returns true if a reading or writing operation fails. For example in the case that we try to write to a file that is not open for writing or if the device where we try to write has no space left. fail( ) Returns true in the same cases as bad(), but also in the case that a format error happens, like when an alphabetical character is extracted when we are trying to read an integer number. eof( ) Returns true if a file open for reading has reached the end. - 52 - good( ) It is the most generic state flag: it returns false in the same cases in which calling any of the previous functions would return true. In order to reset the state flags checked by any of these member functions, we can use the member function clear ( ), which takes no parameters. Header files Getting a stream Three streams just exist: cout (terminal output), cin (terminal input), and cerr (error output, which also goes to the terminal). File streams are of type ifstream (input) or ofstream (output). ifstream fp_in; // declarations of streams fp_in and fp_out ofstream fp_out; fp_in.open("myfile.txt", ios::in); // open the streams fp_out.open("myfile.txt", ios::out); fp_in.close(); // close the streams fp_out.close(); A file should be closed if you are done with it, but the program will continue running for a while longer. This is particularly important when you intend to open a lot of files, as there may be a limit on how many you can have open at once. It is also a good idea if you intend to open a file for input, and then re-open the file for output. Declaring the pointer and opening the file can be combined: ifstream fp_in("myfile.txt", ios::in); // declare and open The parameters ios::in and ios::out specify the mode in which the file is to be opened. Depending on the implementation of C++, it may be possible to specify a variety of other mode options, such as appending to the end of an existing file, triggering an error rather than overwriting an existing file, or specifying that a file is binary for operating systems (e.g. MS-DOS) which distinguish binary and ASCII files. - 53 - Passing streams to functions File streams must be passed to functions by reference, not by value. void myfunction(ifstream &fp, ...) // use this void myfunction(ifstream fp, ...) // not this If you pass streams by value, the C++ compiler will not complain. However, mysterious bad things will start happening, often in parts of the code which don't appear to be related to the offending function. Item by item input and output If each input item is surrounded by whitespace (blanks, tabs, newlines), the items can be read easily using the extraction operator >>. int myinteger; // declarations float myfloat; char mychar; char *mystring; // two ways to declare a string char mystring[64]; fp_in >> myinteger; // input from file pointer or standard input cin >> myfloat; fp_in >> mychar; cin >> mystring; The extraction operator works for numbers (ints, floats), characters (char), and strings (declared as arrays of type char or pointers to type char). The extraction operator returns a zero value if it encounters a problem (typically, the end of the file). Therefore, it can be used as the test in an if statement or a while loop. WARNING: when reading data into a character string, bad things will happen if the input word is longer than your string. To avoid problems, use the operator setw to force excessively long input to be broken up. (You must include the iomanip header file.) The input to setw should be the length of your string (including the null character '\0' at the end of the string). - 54 - cin >> setw(length) >> mystring; Numbers, characters, and strings can be written to a file, standard output, or the standard error using the insertion operator <<. cout << "Value of myinteger " << myinteger << endl; cout << "My string is " << mystring << " plus a null character\n" << flush; To insert a line break, either insert the magic variable endl or write the end- of-line character ('\n') to the output. To make a pointer print out as a pointer, not as whatever type of data it points to, cast it to the type (void *). To make a character print as a number, cast it to type int. Similarly, you can use a cast to convince C++ to print an integer as the corresponding character. cout << (void *)ptr; cout << (int)ch; cout << (char)ival; Buffering and flush When you send output to a stream, it does not necessarily get printed immediately. Rather, it may wait in a buffer until some unspecified event, e.g. buffer full enough, reading from input, or exit from program. The details may vary. Buffering makes it faster to print a large amount of output, particularly if you are producing the output bit-by-bit (e.g. one character at a time). However, it is a nuisance for output used in debugging (e.g. a statement that informs you that step 3 of your algorithm has been finished). Forcing all buffered output to actually be printed is known as "flushing" the stream. A flush can be forced by calling the flush function associated with - 55 - each output stream, inserting the magic variable flush into the stream, or inserting endl. cout << flush; cout.flush(); cout << endl; Other input operations ifstream fp_in; fp_in.get(char &ch) Puts the next input character in the variable ch. Returns an integer value, which is zero if it encountered a problem (e.g. end of file). fp_in.getline(char *buffer, int length) Reads characters into the string buffer, stopping when (a) it has read length- 1 characters or (b) when it finds an end-of-line character ('\n') or the end of the file. Stores a null character ('\0') after the last character read. fp_in.read(char *buffer, int n) Reads n bytes (or until the end of the file) from the stream into the buffer. fp_in.gcount() Returns the number of characters read by a preceding get, getline, or read command. fp_in.ignore(int n) Remove the next n characters (or until end of file) from the input stream, throwing them away into the Great Bit Bucket. cin.putback(char ch) Puts character ch back onto the stream. Bad things will happen if this character is not the one most recently extracted from the stream. These operations all return zero if something goes wrong, e.g. they hit the end of the file. Therefore, they can be used as the condition in an if statement or while loop. - 56 - In addition, there are two more input operations, get and peek. These functions return EOF (which is secretly -1) if they encounter the end of the file. The output of these functions should be put into an integer (not a char) variable. fp_in.get( ) ; Returns the next character in the stream. fp_in.peek( ); Returns the next character in the stream but does not remove it from the stream. Other output operations ofstream fp_out; Other options for writing data to an output stream are: fp_out.put(char ch) Puts ch onto the stream. fp_out.write(char *str, int n) Puts n characters onto the stream, reading them from the string str. Repositioning and error states In general, it is possible to move to any position in a file stream. This is a capability most programmers use rarely, if at all. For fairly obvious reasons, don't try to use repositioning operations on the standard input, output, or error streams. The most likely reason for using a repositioning command is to rewind a file to the start, so that you can read its contents again. This is done as follows: fp_in.clear(); // forget we hit the end of file fp_in.seekg(0, ios::beg); // move to the start of the file List of Exercises 1. Create a user defined manipulator for displaying the details of employees in a neat table format. (Hint: Employee details can be maintained as array of structures). 2. Write a c++ program to create a sequential file and to write 20 random integer numbers in the range 0 to 50 in that file. Now check the file and display on screen, all numbers < 20 from that file. - 57 - 3. Write a c++ program to read a list containing book name, book code and book cost from user interactively. Produce the following output. _________________________________________ NAME CODE COST ________________________________________ Turbo c++ 1001 $$$$250.95 C++ Primer 21 $$$$$$5.00 _________________________________________ 4. Write a C++ program to copy the contents of one text file to another text file. 5. A file is required to record a city’s daily temperature, humidity and barometric pressure for one month. Design a program which first creates this file. It should then open the file for reading and compute and displays the largest, smallest, and average values of the temperature, humidity and barometric pressure data tat are recorded in the file. 6. Write a C++ program to open two files containing integers (in sorted order) and merge their contents. Viva Questions 1. What is a stream? 2. What is the difference in using manipulators and ios functions? 3. What is file mode? Describe the various file mode options available. 4. Describe the approaches used to detect end-of-file condition. 5. What are the different types of errors that might pop-up while processing files? 6. What are the differences between sequential and random files? Learning Outcome At the end of this experiment, the students will be able to Work with stream i/o manipulators Will know how to create user defined manipulators Will know how to open, process and close a text file. - 58 - 10.Templates Function Templates and Class Templates Aim To learn about generic programming To know how to implement function templates and class templates Theory Templates are very useful when implementing generic constructs like vectors, stacks, lists, queues which can be used with any arbitrary type. C++ templates provide a way to re-use source code as opposed to inheritance and composition which provide a way to re-use object code. C++ provides two kinds of templates: class templates and function templates. Use function templates to write generic functions that can be used with arbitrary types. For example, one can write searching and sorting routines which can be used with any arbitrary type. The Standard Template Library generic algorithms have been implemented as function templates, and the containers have been implemented as class templates. Class Templates A class template definition looks like a regular class definition, except it is prefixed by the keyword template. For example, here is the definition of a class template for a Stack. template <class T> class Stack { public: Stack(int = 10) ; ~Stack() { delete [] stackPtr ; } int push(const T&); int pop(T&) ; int isEmpty()const { return top == -1 ; } int isFull() const { return top == size - 1 ; } private: int size ; // number of elements on Stack. int top ; T* stackPtr ; } ; - 59 - T is a type parameter and it can be any type. For example, Stack<Token>, where Token is a user defined class. T does not have to be a class type as implied by the keyword class. For example, Stack<int> and Stack<Message*> are valid instantiations, even though int and Message* are not "classes". Implementing class template member functions Implementing template member functions is somewhat different compared to the regular class member functions. The declarations and definitions of the class template member functions should all be in the same header file. The declarations and definitions need to be in the same header file. Consider the following. //B.H template <class t> class b { public: b() ; ~b() ; } ; // B.CPP # include "B.H" template <class t> b<t>::b() { } template <class t> b<t>::~b() { } //MAIN.CPP # include "B.H" void main() { b<int> bi ; b <float> bf ; } When compiling B.cpp, the compiler has both the declarations and the definitions available. At this point the compiler does not need to generate any definitions for template classes, since there are no instantiations. When the compiler compiles main.cpp, there are two instantiations: template class B<int> and B<float>. At this point the compiler has the declarations but no definitions! Using a class template Using a class template is easy. Create the required classes by plugging in the actual type for the type parameters. This process is commonly known as "Instantiating a class". - 60 - Example typedef Stack<float> FloatStack ; FloatStack fs(5) ; A good programming practice is using typedef while instantiating template classes. Then throughout the program, one can use the typedef name. There are two advantages: Function Templates To perform identical operations for each type of data compactly and conveniently, use function templates. You can write a single function template definition. Based on the argument types provided in calls to the function, the compiler automatically instantiates separate object code functions to handle each type of call appropriately. The STL algorithms are implemented as function templates. Implementing Template Functions Function templates are implemented like regular functions, except they are prefixed with the keyword template. Here is a sample with a function template. # include <iostream> using namespace std ; //max returns the maximum of the two elements template <class T> T max(T a, T b) { return a > b ? a : b ; } Using Template Functions Using function templates is very easy: just use them like regular functions. When the compiler sees an instantiation of the function template, for example: the call max(10, 15) in function main, the compiler generates a function max(int, int). Similarly the compiler generates definitions for max(char, char) and max(float, float) in this case. # include <iostream> using namespace std ; //max returns the maximum of the two elements - 61 - template <class T> T max(T a, T b) { return a > b ? a : b ; } void main() { cout << "max(10, 15) = " << max(10, 15) << endl ; cout << "max('k', 's') = " << max('k', 's') << endl ; cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ; } Template Instantiation When the compiler generates a class, function or static data members from a template, it is referred to as template instantiation. • A class generated from a class template is called a generated class. • A function generated from a function template is called a generated function. • A static data member generated from a static data member template is called a generated static data member. The compiler generates a class, function or static data members from a template when it sees an implicit instantiation or an explicit instantiation of the template. Templates and Friends Friendship can be established between a class template and a global function, a member function of another class (possibly a template class), or even an entire class (possible template class). The table below lists the results of declaring different kinds of friends of a class. Class Template friend declaration in class template X Results of giving friendship template class <T> class X friend void f1() ; makes f1() a friend of all instantiations of template X. For example, f1() is a friend of X<int>, X<A>, and X<Y>. - 62 - template class <T> class X friend void f2(X<T>&) ; For a particular type T for example, float, makes f2(X<float>&) a friend of class X<float> only. f2(x<float>&) cannot be a friend of class X<A>. template class <T> class X friend A::f4() ; // A is a user defined class with a member function f4() ; makes A::f4() a friend of all instantiations of template X. For example, A::f4() is a friend of X<int>, X<A>, and X<Y>. template class <T> class X friend C<T>::f5(X<T>&) ; // C is a class template with a member function f5 For a particular type T for example, float, makes C<float>::f5(X<float>&) a friend of class X<float> only. C<float>::f5(x<float>&) cannot be a friend of class X<A>. template class <T> class X friend class Y ; makes every member function of class Y a friend of every template class produced from the class template X. template class <T> class X friend class Z<T> ; when a template class is instantiated with a particular type T, such as a float, all members of class Z<float> become friends of template class X<float>. List of Exercises 1. Write a function template for finding the minimum value contained in an array. 2. Write a C++ program to represent a stack data structure using class template. 2. Write a class template to represent generic vector include member function to perform following tasks. a. To create a vector. b. To modify the value of given element. c. To multiply by scalar value. d. To display the vector in the form (a,b,c,..) - 63 - Viva Questions 1. What is meant by generic programming? 2. How the compiler processes calls to a function template? 3. How the compiler processes calls to a class template? 4. Distinguish between overloaded function and function template. Learning Outcome At the end of this experiment, the students will be able to Understand the need for generic programming Know how to develop C++ program using class template and function template - 64 - 11. Exception Handling Aim To understand the importance of fault tolerance in programming To learn how to handle exceptions . Theory Exceptions provide a way to react to exceptional circumstances (like runtime errors) in our program by transferring control to special functions called handlers. To catch exceptions we must place a portion of code under exception inspection. This is done by enclosing that portion of code in a try block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored. A exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword catch, which must be placed immediately after the try block: int main ( ) { try { throw 20; } catch (int e) { cout << "An exception occurred. Exception Nr. " << e << endl; } return 0; } Here An exception is occurred and its exception Number. is 20. The code under exception handling is enclosed in a try block. A throw expression accepts one parameter (in this case the integer value 20), which is passed as an argument to the exception handler. The exception handler is declared with the catch keyword. As you can see, it follows immediately the closing brace of the try block. The catch format is similar to a regular function that always has at least one parameter. The - 65 - type of this parameter is very important, since the type of the argument passed by the throw expression is checked against it, and only in the case they match, the exception is caught. We can chain multiple handlers (catch expressions), each one with a different parameter type. Only the handler that matches its type with the argument specified in the throw statement is executed. If we use an ellipsis (...) as the parameter of catch, that handler will catch any exception no matter what the type of the throw exception is. This can be used as a default handler that catches all exceptions not caught by other handlers if it is specified at last: try { // code here } catch (int param) { cout << "int exception"; } catch (char param) { cout << "char exception"; } catch (...) { cout << "default exception"; } In this case the last handler would catch any exception thrown with any parameter that is neither an int nor a char. After an exception has been handled the program execution resumes after the try-catch block, not after the throw statement!. It is also possible to nest try-catch blocks within more external try blocks. In these cases, we have the possibility that an internal catch block forwards the exception to its external level. This is done with the expression throw; with no arguments. For example: try { try { // code here } catch (int n) { hrow; } } catch (...) { out << "Exception occurred"; } - 66 - Exception specifications When declaring a function we can limit the exception type it might directly or indirectly throw by appending a throw suffix to the function declaration: float myfunction (char param) throw (int); This declares a function called myfunction which takes one argument of type char and returns an element of type float. The only exception that this function might throw is an exception of type int. If it throws an exception with a different type, either directly or indirectly, it cannot be caught by a regular int-type handler. If this throw specifier is left empty with no type, this means the function is not allowed to throw exceptions. Functions with no throw specifier (regular functions) are allowed to throw exceptions with any type: int myfunction (int param) throw(); // no exceptions allowed int myfunction (int param); // all exceptions allowed Standard exceptions The C++ Standard library provides a base class specifically designed to declare objects to be thrown as exceptions. It is called exception and is defined in the <exception> header file under the namespace std. This class has the usual default and copy constructors, operators and destructors, plus an additional virtual member function called what that returns a null-terminated character sequence (char *) and that can be overwritten in derived classes to contain some sort of description of the exception. // standard exceptions #include <iostream> #include <exception> using namespace std; class myexception: public exception { virtual const char* what() const throw() { return "My exception happened"; } } myex; - 67 - int main () { try { throw myex; } catch (exception& e) { cout << e.what() << endl; } return 0; } We have placed a handler that catches exception objects by reference (notice the ampersand & after the type), therefore this catches also classes derived from exception, like our myex object of class myexception. All exceptions thrown by components of the C++ Standard library throw exceptions derived from this std::exception class. These are: exception description bad_alloc thrown by new on allocation failure bad_cast thrown by dynamic_cast when fails with a referenced type bad_exception thrown when an exception type doesn't match any catch bad_typeid thrown by typeid ios_base::failure thrown by functions in the iostream library For example, if we use the operator new and the memory cannot be allocated, an exception of type bad_alloc is thrown: try { int * myarray= new int[1000]; } catch (bad_alloc&) { cout << "Error allocating memory." << endl; } - 68 - It is recommended to include all dynamic memory allocations within a try block that catches this type of exception to perform a clean action instead of an abnormal program termination, which is what happens when this type of exception is thrown and not caught. If you want to force a bad_alloc exception to see it in action, you can try to allocate a huge array; On my system, trying to allocate 1 billion ints threw a bad_alloc exception. List of Exercises 1. Design two functions with an exception-specification lists as follows: a) A function which can throw only an integer exception b) A function which can throw only a string exception Design a main( ) function with a try block that is used to test and handle exceptions thrown by these two functions. 2. Write a C++ program to handle divide by zero exception. 3. Write a C++ program to handle array out of bound exception. 4. Write a C++ program to find the roots of a quadratic equation. Throw an exception whenever an imaginary root is found. 5. Write a C++ program to process memory allocation error using exception handling mechanism. 6. Write C++ programs handle multiple catch block, default catch block and rethrowing exceptions for your own problem situation. Viva Questions 1. What happens when a raised exception is not handled by a catch block? 2. When memory allocation fails, how does the new operator notify the error to the caller? 3. What should be placed inside a catch block? 4. Why should we rethrow an exception? 5. When do we use multiple catch handlers? - 69 - Learning Outcome At the end of this experiment, the students will be able to Know how to handle the exception in C++ language1 How to rethrow the exception How to handle exception using functions. - 70 - Appendix A: C++ Reserved Words C++ reserves some words for its own use in the libraries. These words have special “meaning” to the compiler and therefore can not be used as identifiers in a declaration statement. Reserved words are classified into three categories: C++ Keywords asm auto bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum explicit export extern false float for friend goto if inline int long mutable namespace new operator private protected public register reinterpret_cast while return short signed sizeof static static_cast struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile wchar_t Alternative Tokens Alternative tokens are the equivalences of operators at the right side of the following list. Token Meaning and && and_eq &= bitand & bitor | compl ~ not ! not_e != or || or_eq |= xor ^ xor_eq ^= - 71 - Appendix B: Programming Guidelines Remember the divide and conquer principle. If the problem you’re looking at is too confusing, try to imagine what the basic operation of the program would be, given the existence of a magic “piece” that handles the hard parts. That “piece” is an object – write the code that uses the object, then look at the object and encapsulate its hard parts into other objects, etc. Dont automatically rewrite all your existing C code in C++ unless you need to significantly change its functionality (that is, don’t fix it if it isn’t broken). Recompiling C in C++ is a valuable activity because it may reveal hidden bugs. However, taking C code that works fine and rewriting it in C++ may not be the best use of your time, unless the C++ version will provide a lot of opportunities for reuse as a class. If you do have a large body of C code that needs changing, first isolate the parts of the code that will not be modified, possibly wrapping those functions in an “API class” as static member functions. Then focus on the code that will be changed, Refactoring it into classes to facilitate easy modifications as your maintenance proceeds. When you create a class, make your names as clear as possible. Your goal should be to make the client programmer’s interface conceptually simple. Attempt to make your names so clear that comments are unnecessary. To this end, use function overloading and default arguments to create an intuitive, easy- to-use interface. Access control allows you (the class creator) to change as much as possible in the future without damaging client code in which the class is used. In this light, keep everything as private as possible, and make only the class interface public, always using functions rather than data. Make data public only when forced. If class users don’t need to access a function, make it private. If a part of your class must be exposed to inheritors as protected, provide a function interface rather than expose the actual data. In this way, implementation - 72 - changes will have minimal impact on derived classes. Don’t fall into analysis paralysis. There are some things that you don’t learn until you start coding and get some kind of system working. C++ has built-in firewalls; let them work for you. Your mistakes in a class or set of classes won’t destroy the integrity of the whole system. Your analysis and design must produce, at minimum, the classes in your system, their public interfaces, and their relationships to other classes, especially base classes. If your design methodology produces more than that, ask yourself if all the pieces produced by that methodology have value over the lifetime of the program. If they do not, maintaining them will cost you. Members of development teams tend not to maintain anything that does not contribute to their productivity; this is a fact of life that many design methods don’t account for. Make classes as atomic as possible; that is, give each class a single, clear purpose. If your classes or your system design grows too complicated, break complex classes into simpler ones. The most obvious indicator of this is sheer size: if a class is big, chances are it’s doing too much and should be broken up. Watch for long member function definitions. A function that is long and complicated is difficult and expensive to maintain, and is probably trying to do too much all by itself. If you see such a function, it indicates that, at the least, it should be broken up into multiple functions. It may also suggest the creation of a new class. Watch for long argument lists. Function calls then become difficult to write, read and maintain. Instead, try to move the member function to a class where it is (more) appropriate, and/or pass objects in as arguments. Dont repeat yourself. If a piece of code is recurring in many functions in derived classes, put that code into a single function in the base class and call it from the derived-class functions. Not only do you save code space, you provide for easy propagation of changes. You can use an inline function for efficiency. - 73 - Sometimes the discovery of this common code will add valuable functionality to your interface. Watch for switch statements or chained if-else clauses. This is typically an indicator of type-check coding, which means you are choosing what code to execute based on some kind of type information (the exact type may not be obvious at first). You can usually replace this kind of code with inheritance and polymorphism; a polymorphic function call will perform the type checking for you, and allow for more reliable and easier extensibility. From a design standpoint, look for and separate things that change from things that stay the same. That is, search for the elements in a system that you might want to change without forcing a redesign, then encapsulate those elements in classes. Watch out for variance. Two semantically different objects may have identical actions, or responsibilities, and there is a natural temptation to try to make one a subclass of the other just to benefit from inheritance. This is called variance, but there’s no real justification to force a superclass/subclass relationship where it doesn’t exist. A better solution is to create a general base class that produces an interface for both as derived classes – it requires a bit more space, but you still benefit from inheritance and will probably make an important discovery about the design. Watch out for limitation during inheritance. The clearest designs add new capabilities to inherited ones. A suspicious design removes old capabilities during inheritance without adding new ones. But rules are made to be broken, and if you are working from an old class library, it may be more efficient to restrict an existing class in its subclass than it would be to restructure the hierarchy so your new class fits in where it should, above the old class. Don’t extend fundamental functionality by subclassing. If an interface element is essential to a class it should be in the base class, not added during derivation. If you’re adding member functions by inheriting, perhaps you should rethink the design. - 74 - Less is more. Start with a minimal interface to a class, as small and simple as you need to solve the problem at hand, but don’t try to anticipate all the ways that your class might be used. As the class is used, you’ll discover ways you must expand the interface. However, once a class is in use you cannot shrink the interface without disturbing client code. If you need to add more functions, that’s fine; it won’t disturb code, other than forcing recompiles. But even if new member functions replace the functionality of old ones, leave the existing interface alone (you can combine the functionality in the underlying implementation if you want). If you need to expand the interface of an existing function by adding more arguments, leave the existing arguments in their current order, and put default values on all of the new arguments; this way you won’t disturb any existing calls to that function. Read your classes aloud to make sure they’re logical, referring to the relationship between a base class and derived class as “is-a” and member objects as “has-a.” When deciding between inheritance and composition, ask if you need to upcast to the base type. If not, prefer composition (member objects) to inheritance. This can eliminate the perceived need for multiple inheritance. If you inherit, users will think they are supposed to upcast. Sometimes you need to inherit in order to access protected members of the base class. This can lead to a perceived need for multiple inheritance. If you don’t need to upcast, first derive a new class to perform the protected access. Then make that new class a member object inside any class that needs to use it, rather than inheriting. Typically, a base class will be used primarily to create an interface to classes derived from it. Thus, when you create a base class, default to making the member functions pure virtual. The destructor can also be pure virtual (to force inheritors to explicitly override it), but remember to give the destructor a function body, because all destructors in a hierarchy are always called. - 75 - When you put a virtual function in a class, make all functions in that class virtual, and put in a virtual destructor. This approach prevents surprises in the behavior of the interface. Only start removing the virtual keyword when you’re tuning for efficiency and your profiler has pointed you in this direction. Use data members for variation in value and virtual functions for variation in behavior. That is, if you find a class that uses state variables along with member functions that switch behavior based on those variables, you should probably redesign it to express the differences in behavior within subclasses and overridden virtual functions. If you must do something nonportable, make an abstraction for that service and localize it within a class. This extra level of indirection prevents the non- portability from being distributed throughout your program. Avoid multiple inheritance. It’s for getting you out of bad situations, especially repairing class interfaces in which you don’t have control of the broken class. Dont use private inheritance. Although it’s in the language and seems to have occasional functionality, it introduces significant ambiguities when combined with run-time type identification. Create a private member object instead of using private inheritance. If two classes are associated with each other in some functional way (such as containers and iterators), try to make one a publicnested friend class of the other, as the Standard C++ Library does with iterators inside containers. It allows the class name to be reused by nesting it within another class. The other reason you’ll want to nest a class is as part of the private implementation. Here, nesting is beneficial for implementation hiding rather than the class association and prevention of namespace pollution noted above. Operator overloading is only syntactic sugar:” a different way to make a function call. If overloading an operator doesn’t make the class interface clearer - 76 - and easier to use, don’t do it. Create only one automatic type conversion operator for a class. Dont fall prey to premature optimization. That way lies madness. In particular, don’t worry about writing (or avoiding) inline functions, making some functions non virtual, or tweaking code to be efficient when you are first constructing the system. Your primary goal should be to prove the design, unless the design requires certain efficiency. Normally, dont let the compiler create the constructors, destructors, or the operator= for you. Class designers should always say exactly what the class should do and keep the class entirely under control. If you don’t want a copyconstructor or operator=, declare them as private. Remember that if you create any constructor, it prevents the default constructor from being synthesized. If your class contains pointers, you must create the copy constructor, operator=, and destructor for the class to work properly. When you write a copy-constructor for a derived class, remember to call the base-class copy-constructor explicitly. If you don’t, the default constructor will be called for the base class (or member object) and that probably isn’t what you want. To call the base-class copy-constructor, pass it the derived object you’re copying from: Derived(const Derived& d) : Base(d) { // ... When you write an assignment operator for a derived class, remember to call the base-class version of the assignment operator explicitly. If you don’t, then nothing will happen (the same is true for the member objects). To call the base- class assignment operator, use the base-class name and scope resolution: Derived& operator=(const Derived& d) { Base::operator=(d); Avoid the preprocessor. Always use const for value substitution and inlines for macros. - 77 - Keep scopes as small as possible so the visibility and lifetime of your objects are as small as possible. This reduces the chance of using an object in the wrong context and hiding a difficult-to-find bug. For example, suppose you have a container and a piece of code that iterates through it. If you copy that code to use with a new container, you may accidentally end up using the size of the old container as the upper bound of the new one. If, however, the old container is out of scope, the error will be caught at compile time. Avoid global variables. Always strive to put data inside classes. Global functions are more likely to occur naturally than global variables, although you may later discover that a global function may fit better as a static member of a class. If you need to declare a class or function from a library, always do so by including a header file. For example, if you want to create a function to write to an ostream, never declare ostream yourself using an incomplete type specification like this, class ostream; This approach leaves your code vulnerable to changes in representation. (For example, ostream could actually be a typedef.) Instead, always use the header file: #include <iostream>. When creating your own classes, if a library is big, provide your users an abbreviated form of the header file with incomplete type specifications (that is, class name declarations) for cases in which they need to use only pointers. (It can speed compilations.) When choosing the return type of an overloaded operator, consider what will happen if expressions are chained together. Return a copy or reference to the lvalue (return *this) so it can be used in a chained expression (A = B = C). When defining operator=, remember x=x. When writing a function, pass arguments by const reference as your first choice. As long as you don’t need to modify the object being passed, this practice is best because it has the simplicity of pass-by-value syntax but doesn’t require expensive constructions and destructions to create a local object, which - 78 - occurs when passing by value. Normally you don’t want to be worrying too much about efficiency issues when designing and building your system, but this habit is a sure win. Be aware of temporaries. When tuning for performance, watch out for temporary creation, especially with operator overloading. If your constructors and destructors are complicated, the cost of creating and destroying temporaries can be high. When returning a value from a function, always try to build the object “in place” with a constructor call in the return statement: return MyType(i, j); rather than MyType x(i, j); return x; The former return statement (the so-called return-value optimization) eliminates a copy- constructor call and destructor call. When creating constructors, consider exceptions. In the best case, the constructor won’t do anything that throws an exception. In the next-best scenario, the class will be composed and inherited from robust classes only, so they will automatically clean themselves up if an exception is thrown. If you must have naked pointers, you are responsible for catching your own exceptions and then deallocating any resources pointed to before you throw an exception in your constructor. If a constructor must fail, the appropriate action is to throw an exception. Do only what is minimally necessary in your constructors. Not only does this produce a lower overhead for constructor calls (many of which may not be under your control) but your constructors are then less likely to throw exceptions or cause problems. The responsibility of the destructor is to release resources allocated during the lifetime of the object, not just during construction. - 79 - Use exception hierarchies, preferably derived from the Standard C++ exception hierarchy and nested as public classes within the class that throws the exceptions. The person catching the exceptions can then catch the specific types of exceptions, followed by the base type. If you add new derived exceptions, existing client code will still catch the exception through the base type. Throw exceptions by value and catch exceptions by reference. Let the exception-handling mechanism handle memory management. If you throw pointers to exception objects that have been created on the heap, the catcher must know to destroy the exception, which is bad coupling. If you catch exceptions by value, you cause extra constructions and destructions; worse, the derived portions of your exception objects may be sliced during upcasting by value. Dont write your own class templates unless you must. Look first in the Standard C++ Library, then to vendors who create special-purpose tools. Become proficient with their use and you’ll greatly increase your productivity. When creating templates, watch for code that does not depend on type and put that code in a non-template base class to prevent needless code bloat. Using inheritance or composition, you can create templates in which the bulk of the code they contain is type-dependent and therefore essential. Don’t use the <cstdio> functions, such as printf( ). Learn to use iostreams instead; they are type-safe and type-extensible, and significantly more powerful. Your investment will be rewarded regularly. In general, always use C++ libraries in preference to C libraries. Avoid Cs built-in types. They are supported in C++ for backward compatibility, but they are much less robust than C++ classes, so your bug- hunting time will increase. Whenever you use built-in types as globals or automatics, don’t define them until you can also initialize them. Define variables one per line along with their initialization. When defining pointers, put - 80 - the ‘*’ next to the type name. You can safely do this if you define one variable per line. This style tends to be less confusing for the reader. Guarantee that initialization occurs in all aspects of your code. Perform all member initialization in the constructor initializer list, even built-in types (using pseudo-constructor calls). Using the constructor initializer list is often more efficient when initializing subobjects; otherwise the default constructor is called, and you end up calling other member functions (probably operator=) on top of that in order to get the initialization you want. Don’t use the form MyType a = b; to define an object. This one feature is a major source of confusion because it calls a constructor instead of the operator=. For clarity, always be specific and use the form MyType a(b); instead. The results are identical, but other programmers won’t be confused. Use the explicit casts. A cast overrides the normal typing system and is a potential error spot. Since the explicit casts divide C’s one-cast-does-all into classes of well-marked casts, anyone debugging and maintaining the code can easily find all the places where logical errors are most likely to happen. For a program to be robust, each component must be robust. Use all the tools provided by C++: access control, exceptions, const-correctness, type checking, and so on in each class you create. That way you can safely move to the next level of abstraction when building your system. Build in const-correctness. This allows the compiler to point out bugs that would otherwise be subtle and difficult to find. This practice takes a little discipline and must be used consistently throughout your classes, but it pays off. Use compiler error checking to your advantage. Perform all compiles with full warnings, and fix your code to remove all warnings. Write code that utilizes the compile-time errors and warnings rather than that which causes runtime errors (for example, don’t use variadic argument lists, which disable all type checking). Use assert( ) for debugging, but use exceptions for runtime errors. - 81 - Prefer compile-time errors to runtime errors. Try to handle an error as close to the point of its occurrence as possible. Prefer dealing with the error at that point to throwing an exception. Catch any exceptions in the nearest handler that has enough information to deal with them. Do what you can with the exception at the current level; if that doesn’t solve the problem, rethrow the exception. If you’re using exception specifications install your own unexpected( ) function using set_unexpected( ) . Your unexpected( ) should log the error and rethrow the current exception. That way, if an existing function gets overridden and starts throwing exceptions, you will have a record of the culprit and can modify your calling code to handle the exception. Create a user-defined terminate( ) (indicating a programmer error) to log the error that caused the exception, then release system resources, and exit the program. If a destructor calls any functions, those functions might throw exceptions. A destructor cannot throw an exception (this can result in a call to terminate( ), which indicates a programming error), so any destructor that calls functions must catch and manage its own exceptions. Dont create your own decorated private data member names (prepending underscores, Hungarian notation, etc.), unless you have a lot of pre-existing global values; otherwise, let classes and namespaces do the name scoping for you. Watch for overloading. A function should not conditionally execute code based on the value of an argument, default or not. In this case, you should create two or more overloaded functions instead. Hide your pointers inside container classes. Bring them out only when you are going to immediately perform operations on them. Pointers have always been a major source of bugs. When you use new, try to drop the resulting pointer into a container. Prefer that a container “own” its pointers so it’s responsible for cleanup. Even better, wrap a pointer inside a class; if you still want it to look like a pointer, overload operator->and operator*. If you must - 82 - have a free-standing pointer, always initialize it, preferably to an object address, but to zero if necessary. Set it to zero when you delete it to prevent accidental multiple deletions. Dont overload global new and delete; always do this on a class-by-class basis. Overloading the global versions affects the entire client programmer project, something only the creators of a project should control. When overloading new and delete for classes, don’t assume that you know the size of the object; someone may be inheriting from you. Use the provided argument. If you do anything special, consider the effect it could have on inheritors. Prevent object slicing. It virtually never makes sense to upcast an object by value. To prevent upcasting by value, put pure virtual functions in your base class. - 83 - Appendix C: Sample Programs Problem 1 : Write a C++ program to find the area of a rectangle using inline function. Aim To write a c++ program to find the area of a rectangle for its given length and width using inline function. Algorithm 1. Include the necessary header files iostream.h and conio.h 2. Declare and define an inline function find_area( ) with two arguments length and width of float type. 3. Also make the return type of that function as float. 4. The inline function returns the multiplication of length and width. 5. In main function declare necessary variables for length, width and area for the given rectangle. 6. Get input from user for length and width. 7. Call the inline function find_area( ) with user specified length and width. 8. Print the area of the rectangle returned by the inline function Program # include<iostream.h> # include<conio.h> inline float find_area(float length, float width) { return length * width; } int main() { float len, wid, area; clrscr(); cout<<"Enter the length of the rectangle : "; cin>>len; - 84 - cout<<"Enter the width of the rectangle: "; cin>>wid; area=find_area(len,wid); cout<<"Area of rectangle = "<<area; getch(); return 0; } Sample Input Enter the length of the rectangle 10.2 Enter the width of the rectangle 5.1 Sample Output Area of rectangle = 52.02 Result Thus the c++ program to find the area of a rectangle using inline function is created and executed successfully. - 85 - Problem 2: Given that an EMPLOYEE class contains the following members: Data Members: Employee_Number, Employee_Name, Basic, DA, IT, Net_Sal. Member Functions: to read data, to calculate and print Net_Sal. Write a C++ program to read data on N employees and compute the Net_Sal of each employee (DA = 52% of Basic and Income Tax = 30% of the gross salary) Aim To develop a c++ program to represeant an employee details as a class and to calculate and display the salary details using member functions. Alogirthm 1. Include the the necessary header file. 2. Create a class EMPLOYEE with data members employee no, employee name , basic pay, dearness allowance, income tax, and net salary. 3. Also include three member function to read the data calculate net salary and to display data. 4. In the read member function, read employee name, number and basic salary. 5. In calculate_net_salary function, calculate DA, Gross salary, IT and Net salary as follows. DA = 52 % of basic salary Gross Salary = basic+DA Income_tax(IT) = 30 % of gross salary Net salary = Gross_Sal-IT; 6. In display member function, display the employee number, name and net salary detail. 7. In main function, create and object for EMPLOYEE class and call all the member functions. Program # include <iostream.h> # include <conio.h> class EMPLOYEE //implements the EMPLOYEE class { private: - 86 - char employee_number[10],employee_name[10]; float basic,DA, IT, net_sal; public: void Read_Data(); //reads the employee_number, name and basic void Calculate_Net_Salary(); //calculates the net salary void Display_Data(); //Displays the data } ; void EMPLOYEE::Read_Data() { cout << "Enter the Employee Number and Name : " << endl; cin >> employee_number >> employee_name; cout << "Enter the Basic Salary: " << endl; cin >> basic; } void EMPLOYEE::Calculate_Net_Salary() { float Gross_Sal; DA = (52*basic)/100; Gross_Sal = basic+DA; IT = (30*Gross_Sal)/100; net_sal = Gross_Sal-IT; } void EMPLOYEE::Display_Data() { cout << "Emp Name: " << employee_name << "\n"; cout<<"Emp Number: " <<employee_number<<”\n"; cout << "Net Salary: " << net_sal << endl; } int main() { int n,i; clrscr(); cin >> n; cout << endl; EMPLOYEE Emp; cout << "Enter employee data" << endl; Emp.Read_Data(); Emp.Calculate_Net_Salary(); Emp.Display_Data(); } } - 87 - Sample Input Enter the employee data Enter the Employee Number and Name: Ram Emp0010 Enter the Basic Salary: 8500 Sample Output Emp Name : Ram Emp Number: Emp0010 Net Salary: 9044 Result Thus the C++ program to find the employee salary details have been generated by using the concept of classes and executed successfully. - 88 - References [1] Goran Svenk (2002), Object-oriented Programming using C++ for Engineering and Technology, Thomson Delmar Learning. [2] Harvey M. Deitel and Paul J. Deitel (2004), Simply C++ An Application Driven Tutorial Approach, Prentice Hall. [3] E.Balagurusamy, “ Object Oriented Programming with C++”, 4 th edition, Tata Mcgraw Hill. [4] M.T.Somashekara, “ Programming in C++”, July 2009, Prentice Hall of India [5] K.R.Venugopal, Rajkumar, T.Ravishankar (2009), “Mastering C++”, Tata Mcgraw Hill. [6] D.S.Malik, “C++ programming Language”, 4 th edition, Cengage Learning. [7] Bruce Eckel (2000), “Thinking in C++”, 2 nd edition, Prentice Hall. [8] http://www.cplusplus.com [9] http://cpptips.hyperformix.com [10] http://www.learncpp.com/ [11] http://www.cpp4u.com/
Copyright © 2024 DOKUMEN.SITE Inc.