PROGRAMMING USING
C++
BY
Avinash Kumar Singh 1
Avinash Kumar Singh
INDEX SR.NO 1 2 3 4 5 6 7 8 9 10 11 12 13
2
CHAPTERS PROGRAMMING THROUGH C++ PROGRAMMING & ITS VARIOUS TECHNIQUES PRINCIPLES OF OOPS ELEMENTS OF C++ FUNCTIONS OBJECTS & CLASSES CONSTRUCTOR & DESTRUCTOR OPERATOR OVERLOADING & TYPE CONVERSION INHERITANCE POINTERS, VIRTUAL FUNCTIONS & POLYMORPHISMS I/O OPERATIONS WORKING WITH FILES TEMPLATE & EXCEPTION HANDLING
PAGE NO. 3 4 9 23 47 67 83 99 109 115 125 133 138
Avinash Kumar Singh
Programming Through C++ Preface
The lessons of this tutorial will lead you from being a beginning student of C++ up to being a intermediate level C++ programmer. To get good grasp on this tutorial, We will suggest you all to first go through our "C Tutorial" to well understand the common programming term. Before you jump right in, here is the single most important piece of advice which is offered. To learn C++ and to get the most out of these lessons, you need to have access to a compiler. The complier turns the source code files, which are the text you will write, into a form that can be read and executed by a computer. As you work through the tutorials We encourage you to try to compile and run the examples which are provided in the original C++ window. Somewhere you will find out that the output of program is not given because, there we have tried to show you structure and logical view of the program only. We make every effort to create working code rather than code snippets that won't compile or run. The best and most enjoyable way to learn to program is to actually write code. This tutorial is organized topic wise in chapters as follows: 1 Programming and its various techniques 2 Principal of Object Oriented Programming (OOP) 3 Elements of C++ Language 4 Functions 5 Object and Classes 6 Constructors and Destructors 7 Operator Overloading and Type Conversion 8 Inheritance 9 Pointers, Virtual Functions and Polymorphism 10 I/O Operation 11 Working with files 12 Template & Exception Handling
3
Avinash Kumar Singh
Programming and its various techniques Introduction to Programming History
Without a program, a computer has no purpose. It becomes an inert mass, a way to keep a door open when the wind blows.
In 1952, a very clever man named John Von Neumann was working on a rather primitive computer that was programmed by moving wires about on a large plug-board. It occurred to him that the program could be stored within the machine, along with the data, in what we now call “random-access memory.” This research removed the final obstacle to large, complex programs, the ability to switch tasks quickly, and the logical certainly that a program above a certain complexity level cannot be proven to be bug-free.
It can fairly be argued that a computer program is a product of pure intellect, has no physical existence, and therefore cannot meaningfully be secured against theft. To summarize, a computer is a machine whose sole purpose is to faithfully carry out a computer program's instructions. It is no more than an input/output device to support the intellectual goals of a computer program (and a programmer). The computer's higher purpose resides in its program. This is why, as time passes, computers become less expensive and programs become more expensive. It is why the richest man in the world is, not a builder of computers, but a builder of programs.
4
Avinash Kumar Singh
It is why, over time, computer scientists have come to focus more on programming issues and less on hardware issues. It is why, when a government agency decides to upgrade its computers, it is almost always the case that, after billions have been spent, they discover the old software will not run on the new hardware, and they abandon the project.
Various Programming Techniques This section is a short survey of programming techniques. There are various types of programming technique is available in the programming era. Here more focus has been given over OOP. List of Various Programming Technique: 1. Unstructured Programming 2. Procedural Programming 3. Modular Programming 4. Object-Oriented Programming (OOP) Unstructured Programming Usually, people start learning programming by writing small and simple programs consisting only of one main program. Here "main program'' stands for a sequence of commands or statements which modify data which is global throughout the whole program. We can illustrate this as shown below: Unstructured programming. The main program directly operates on global data.
As you should all know, this programming techniques provide tremendous disadvantages once the program gets sufficiently large. For example, if the same statement sequence is needed at different locations within the program, the sequence must be copied. This has lead to the idea to extract these sequences, name them and offering a technique to call and return from these procedures. Procedural Programming With procedural programming you are able to combine returning sequences of statements into one single place. A procedure call is used to invoke the procedure. After 5
Avinash Kumar Singh
the sequence is processed, flow of control proceeds right after the position where the call was made. Execution of procedures. After processing flow of controls proceed where the call was made.
With introducing parameters as well as procedures of procedures (sub procedures) programs can now be written more structured and error free. For example, if a procedure is correct, every time it is used it produces correct results. Consequently, in cases of errors you can narrow your search to those places which are not proven to be correct. Now a program can be viewed as a sequence of procedure calls. The main program is responsible to pass data to the individual calls, the data is processed by the procedures and, once the program has finished, the resulting data is presented. Thus, the flow of data can be illustrated as a hierarchical graph, a tree, as shown below for a program with no sub procedures: In the Procedural programming technique main program coordinates calls to procedures and hands over appropriate data as parameters.
Now we have a single program which is divided into small pieces called procedures. To enable usage of general procedures or groups of procedures also in other programs, they must be separately available. For that reason, modular programming allows grouping of procedures into modules. 6
Avinash Kumar Singh
Modular Programming With modular programming procedures of a common functionality are grouped together into separate modules. A program therefore no longer consists of only one single part. It is now divided into several smaller parts which interact through procedure calls and which form the whole program. Modular programming. The main program coordinates calls to procedures in separate modules and hands over appropriate data as parameters.
Each module can have its own data. This allows each module to manage an internal state which is modified by calls to procedures of this module. However, there is only one state per module and each module exists at most once in the whole program. Object-Oriented Programming Today's large scale software systems are typically designed and implemented using the concepts of the object-oriented model. However, there is still a need for the existing OO languages and architectures to continuously adapt in response to demands for new features and paradigms. These new features include topics such as dynamic software evolution, security, safety, distribution and expressiveness. Object programming is an approach that provides a way of modularizing programs by creating partitioned memory area for both data and functions that can be used as templates for creating copies of such modules on demand. That is, an object is considered to be a partitioned area of computer memory that stores data and set of operations that can access data. Since the memory partitions are independent, the objects can be used in a variety of different program without modifications. In Object-oriented programming technique the Objects of the program interact by sending messages to each other as shown below. 7 Avinash Kumar Singh
Comparison of OOP With other procedural languages: Although the languages share common syntax they are very different in nature. C is a procedural language. When approaching a programming challenge the general method of solution is to break the task into successively smaller subtasks. This is known as topdown design. C++ is an object-oriented language. To solve a problem with C++ the first step is to design classes that are abstractions of physical objects. These classes contain both the state of the object, its members, and the capabilities of the object, its methods. After the classes are designed, a program is written that uses these classes to solve the task at hand. Therefore this features extends many other features of OOP. Those feature we will discuss in the last of this section. "Object -Orientation" remains a term which is interpreted differently by different people. It is therefore necessary to understand some of the concept used extensively in OOP. Which make the features of OOP. We shall discuss the following general concept of OOP below.
8
Avinash Kumar Singh
Principal of Object Oriented Programming (OOP) General Concept of OOP
Object Object is an identifiable run-time entity with some characteristic and behavior. for example 'orange' is an object and its characters are shape, color etc. Class A class is a group of object that share common properties and relationship. for example fruit has been defined as a class, then the statement fruit mango; will create an object mango belonging to the class fruit. Message At runtime instances of classes, the objects, achieve the goal of the program by changing their states. Consequently, we can think of our running program as a collection of objects. The question arises of how these objects interact? We therefore introduce the concept of a message. A running program is a pool of objects where objects are created, destroyed and interacting. This interacting is based on messages which are sent from one object to another asking the recipient to apply a method on itself. A message is a request to an object to invoke one of its methods. A message therefore contains. the name of the method and the arguments of the method.
9
Avinash Kumar Singh
In this figure, the program consists of only four objects. These objects send messages to each other, as indicated by the arrowed lines. Note that the third object sends itself a message. Data Abstraction Abstraction refers to the act of representing essential features without including the background details. To understand abstraction, lets an example. you are driving a car you only know the essential features to drive the car e.g. gear, steering etc. But while driving the car you get into the internal details of the car such as wiring, battery etc. What is happening inside is hidden from you. This is data abstraction where you know only the essential things to drive the car without including the background details. Data Encapsulation Encapsulation is the most fundamental concept of OOP. It is the way of combining both data and the functions that operate on data under a single unit. The wrapping of the data and functions (that operate on the data) into a single unit (called classes) is known as encapsulation. The only way to access the data is provided by the functions (that are combined along with the data). These function are called member functions in C++. The data can not be accessed directly. If you want to read a data item in an object (an instance of a class), you call a member function in the object it will read the items and return the value to you. Encapsulation is just a way to implement data abstraction.
As you know encapsulation is an important feature of C++. How ever, encapsulation provides another important attribute : access control. Through encapsulation you can control what part of program can access the member of a class. C++ specifies three access modes: 10
Avinash Kumar Singh
a) Private: It means can be accessed only with in the class and not by the out side world. It is by default. b) Public: It means visible to all any class in that program can access. c) Protected: It means only visible to those who inherit that class. Inheritance Understanding inheritance is critical to understanding the whole point behind object oriented programming. Definition: Inheritance is the mechanism which allows a class A to inherit properties of a class B. We say "A inherits from B''. Objects of class A thus have access to attributes and methods of class B without the need to redefine them. Inheritance is the capability of one class of things to inherit capabilities or properties from another class. For instance we are humans. We inherit from the class 'humans' certain properties, such as ability to speak, breath eat drink etc but these properties are not unique to the humans it inherit some properties from class called 'Mammals' which again inherit some of its properties from from another class 'Animals'. Another example is the 'Car' inherits its properties from the class 'Automobiles' which inherit its properties from another class 'Vehicles'.
Super Class/Subclass Definition: If class A inherits from class B, then B is called superclass of A. A is called subclass of B. Objects of a subclass can be used where objects of the corresponding superclass are expected. This is due to the fact that objects of the subclass share the same behaviour as objects of the superclass. In the literature you may also find other terms for "superclass'' and "subclass''. Superclasses are also called parent classes. Subclasses may also be called child classes or just derived classes. 11
Avinash Kumar Singh
Of course, We can again inherit from a subclass, making this class the superclass of the new subclass. This leads to a hierarchy of superclass/subclass relationships. If you draw this hierarchy you get an inheritance graph. A common drawing scheme is to use arrowed lines to indicate the inheritance relationship between two classes or objects. In our examples we have used "inheritsfrom''. Consequently, the arrowed line starts from the subclass towards the superclass as illustrated in below figure: A simple inheritance graph.
In the following sections an unmarked arrowed line indicates "inherit-from''. Static and Dynamic Binding In strongly typed programming languages you typically have to declare variables prior to their use. This also implies the variable's definition where the compiler reserves space for the variable. For example, in Pascal an expression like: var i : integer; declares variable i to be of type integer. Additionally, it defines enough memory space to hold an integer value. With the declaration we bind the name i to the type integer. This binding is true within the scope in which i is declared. This enables the compiler to check at compilation time for type consistency. For example, the following assignment will result in a type mismatch error when you try to compile it: var i : integer; ... i := 'string'; We call this particular type of binding "static'' because it is fixed at compile time. If the type T of a variable is explicitly associated with its name N by declaration, we say, that N is statically bound to T. The association process is called static binding. 12
Avinash Kumar Singh
There exist programming languages which are not using explicitly typed variables. For example, some languages allow to introduce variables once they are needed: ... /* No appearance of i */ i := 123 /* Creation of i as an integer */ The type of i is known as soon as its value is set. In this case, i is of type integer since we have assigned a whole number to it. Thus, because the content of i is a whole number, the type of i is integer. If the type T of a variable with name N is implicitly associated by its content, we say, that N is dynamically bound to T. The association process is called dynamic binding. Both bindings differ in the time when the type is bound to the variable. Consider the following example which is only possible with dynamic binding: if somecondition() == TRUE then n := 123 else n := 'abc' endif The type of n after the if statement depends on the evaluation of somecondition(). If it is TRUE, n is of type integer whereas in the other case it is of type string. Polymorphism Polymorphism allows an entity (for example, variable, function or object) to take a variety of representations. Polymorphism is key to the power of object oriented programming. It is so important that languages don't support support polymorphism can not advertise them self as OO languages. Polymorphism is the ability for a message or data to be processed in more than one form. Polymorphism is a concept that support the capability of an object of a class to behave differently in response to a message or action. Polymorphism is a property by which the same message can be sent to objects of several different classes, and each object can be respond in a different way depending on its class.
13
Avinash Kumar Singh
Abstract Classes We introduce the new keyword abstract here. It is used to express the fact that derived classes must "redefine'' the properties to fulfill the desired functionality. Thus from the abstract class' point of view, the properties are only specified but not fully defined. The full definition including the semantics of the properties must be provided by derived classes. A class A is called abstract class if it is only used as a superclass for other classes. Class A only specifies properties. It is not used to create objects. Derived classes must define the properties of A. Template class Definition: If a class A is parameterized with a data type B, A is called template class. Once an object of A is created, B is replaced by an actual data type. This allows the definition of an actual class based on the template specified for A and the actual data type. Benefit of OOP Some of the benefit of using OOP given here: 1. Through inheritance, we can eliminate redundant code and extend the use of existing classes. 2. Software complexity can be easily managed. 3. Object oriented system can be easily upgraded from small to large system. 4. It is easy to Partition the work in a project based on object. 5. We can build program from the standard working modules that communicate with one another, rather than having to start writing the code from scratch. 6. Message passing techniques for communication between object makes the interface description with external system much simpler etc. Overview of OOP using C++ A Brief History Of C++ Bjarne Stroustrup at Bell Labs initially developed C++ during the early 1980's. It was designed to support the features of C such as efficiency and low-level support for system level coding. Initially it was called "C with classes" however in 1983 the name was changed to C++ because is was an extends C by a special feature classes. Added to this were features such as classes with inheritance and virtual functions, derived from the Simula67 language, and operator overloading, derived from Algol68. Don't worry about understanding all the terms just yet, they are explained in above section. C++ is best described as a superset of C, with full support for object-oriented programming. This language is in wide spread use. The need for C++ During the late 1970s and early 1980s, C became the dominant computer programming language, and it is still widely used today Since C is a successful and useful language but there arise a need for something else existed, the reason is complexity. 14
Avinash Kumar Singh
Need arise due to complexity and C++ is a response for that need. Once a project reaches a certain size, its complexity exceeds what a programmer can manage. By the early 1980s, many projects were publishing the structured approach past its limits. To solve the problem, a new way to programming was invented, called object-oriented. Introduction of C++ C++ is an advanced, powerful language, yet it is relatively easy to introduce and learn. it is most modern, high-performance computer programs are written using C++. C++ knows about objects and therefore can teach sound programming techniques from the very beginning. C++ is a compiled computer language. This means the original source code is translated into a specific machine's native tongue, all at once, before the program is run. The program the computer runs is composed entirely of instructions known to it, requiring no further interpretation. Below a picture has been given to understand so how c++ source code translate into machine code: Source Code #include
int main() { cout << "Bonjour Monde!" << endl; return 0; } Compiler A compiler is a very specialized computer program that translates source code into machine-specific code. Compiler writing is very difficult and esoteric, and is one of the more advanced and complex parts of computer science. It is not too much to say that a compiler writer is to a computer programmer as a computer programmer is to someone who thinks they speak Latin in Latin America. Machine-Specific Code F000:0000 F0 LOCK F000:0001 8AC4 MOV AL,AH F000:0003 9A5CF000F0 CALL F000:F05C F000:0008 EBEA JMP FFF4 F000:000A 8AC2 MOV AL,DL F000:000C 02C6 ADD AL,DH F000:000E 52 PUSH DX F000:000F BA8103 MOV DX,0381 F000:0012 9AD44500F0 CALL F000:45D4 F000:0017 5A POP DX 15
Avinash Kumar Singh
F000:0018 F000:0019 F000:001A F000:001B F000:001C F000:001D F000:001F F000:0020
5A 59 58 CB 56 D000 F0 82D000
POP POP POP RETF PUSH ROL LOCK ADC
DX CX AX SI BYTE PTR [BX+SI],1 AL,00
... and so on, for hundreds of lines. Note This code only show how the program of c++ language converted into machine language. Note:-There is no need to learn these codes to learn c++. The other major approach to running a computer program is called interpretation. An interpreter converts a computer program into the host machine's native tongue, instruction by instruction, as the program runs. This is a nice environment in which to write programs, but if the program is simply used and is no longer being developed, much time is wasted re-interpreting instructions that could be translated just once and stored in translated form. Because a compiler translates the entire program at once, compiled programs are faster than interpreted programs, and are preferred for tasks that require high performance. There are two principal reasons for high-level languages like C++. The first is to make program development easier each instruction written in C++ might represent dozens or hundreds of lower-level native instructions. The second is to make programs portable if sufficient care is taken in development, a program written for one computer can be re-compiled and run on another. Therefore, a programmer need only learn one computer language, instead of one language per computer architecture. If a single program can be run on any machine, the unit price of software can go down. It would be nice if there were an interpreted version of C++, for program development work only, so the developer would not have to recompile after each trivial change. But this hasn't happened yet, and in any case it would probably be an expensive environment. C++ is a third generation programming language. When computers were first invented, they were programmed with very simple, low-level commands. A programmer would design a program, then translate the program into a specific set of codes, known as machine language. These codes would be fed into a computer with switches, punch-cards, or primitive keypads. These programs were cumbersome to write, and very hard to debug 16
Avinash Kumar Singh
(Debugging is the act of removing mistakes in a program). Machine code is considered the first generation of programming languages. Third generation languages are compiled languages. These languages are not processorspecific. In theory, a program written in a third generation language will be able to run on any other machine. This is not always the case, due to a number of factors. Third generation languages are much more abstract than assembly languages. Third generation languages are translated into assembly language by a complicated piece of software called a compiler. A compiler can be thought of a a language translator.
C++ is a very useful language, because it gives the programmer a lot of control, but also is abstract enough so development can be done fairly quickly. C++ is a very portable language as well, because it is a third-generation language, and because it has a well defined set of standards written for it. C++ is widely used for program development under a variety of operating systems. Good C++ programmers are in high demand today. An Introduction to the program block of C++ Filename A source file is the file that contains the C++ code that is compiled into an executable file, using a C++ compiler. C++ source files usually have an extension name of cpp, or cxx, depending on the compiler. Library Files Like C, C++ has a limited number of keywords, and depends on Library Files for its functionality. This functionality is achieved by using library files. These library files are referred to as Header files and have a .h extension name. The standard input/output header file is called iostream.h. The #include statement is used to insert the header code so your program may use the functions defined in the header file. Angled brackets are used to instruct the preprocessor to find the header files from the standard header file directory. The following illustrates how to include the iostream.h file: #include Comments There are two types of comments in C++: 1. Block Comments: Block comments span several lines. The characters /* start a block comment, and the characters */ end the block comment. 17
Avinash Kumar Singh
/* This is a block comment. The body of the comment is placed over several lines. The comment ends when the terminating characters are provided. */ 2. In-Line Comments: An in-line comment is a comment that is on a single line. Inline comments do not require termination characters, as they're automatically terminated at the end of the line. The characters // are used to start an inline comment. // This is an in-line comment Nested block comments are not allowed in C++. The following causes an error. /* Start of a block comment. /* An illegal nested comment */ End of a block comment. */ Inline comments may be nested within block comments, or even inline comments. /* Start of a block comment. // A legal inline nested // comment End of a block comment. */ Preprocessor Directives Before the program is compiled, the source code is scanned by a preprocessor to perform text substitution, and header file inclusions. C++ supports inline functions, and constants, so is consequently more often used just for header file inclusion and conditional compilation statements. Preprocessor directives are preceded with a #. The # should always be placed in the first column of the line. The following is a directive that causes the contents of the header file to be brought into the current file, effectively replacing the directive line with the contents of that file. #include The main Function Most C++ programs have one main( ) function, with the exception of Dynamic Link Libraries (DLL's) in Windows. The main( ) function is the starting point of the program. The ANSI C++ definition for declaring the main( ) function is either: int main() Or int main(int argc, char **argv) The second definition is used with Command Line Arguments and shall be covered later. The int keyword means that the program should return an integer (whole number) to the operating system, signifying success or failure. A return value of zero indicates success. Each statement within the main function or any other functions should be tabbed in (indented) to show the structure. The braces are used to group the statements within the function together. 18
Avinash Kumar Singh
The following is the basic structure of a C++ source file: #include int main() { // Statements belonging to the function are tabbed return 0; }
A sample C++ program "WELCOME TO EBIZ": Here's the traditional first program for newcomers to C++. Create a new source file using your IDE or text editor and type in the code below:
Output of the program:
Analyzing the structure of the program: Let's take a look at the above program line by line. Firstly: #include This is an include statement and tells the compiler to make the contents of the header available to the program. The input and output streams cin and cout, used in our program to read keyboard input and output to the display screen, are defined in . If you try to compile the code without including this header it will fail to compile. 19 Avinash Kumar Singh
The header is a standard library header and in common with all of the standard C++. int main() The above line is the start of the definition of function main(). All C++ programs must have a main() function which is the entry point to the program. A typical C++ program in the real world will have many functions. In our simple case, we can put all of our code into the one function, main(). { The opening brace, above, marks the start of a code block. In this case it marks the start of function main(). For every opening brace in a program there will be a corresponding closing brace marking the end of the code block. cout << "WELCOME TO EBIZ" << endl; This is where the real work is done in our simple program. Here the string "Hello, world" is output via the output stream, cout. The endl manipulator outputs a newline and then flushes the stream. Because cout is buffered, output may not be displayed when first written. Flushing the stream forces the contents of the buffer to be output. cin.get(); The line above causes the program to wait for input from the cin input stream. This may not be required, however, there are some programming environments, for instance running a console program in a Microsoft Windows environment, where the output may disappear before you've had an opportunity to see it when the program completes. Adding this line of code will enable you to see the output, and then press Enter to continue. If not required for your environment you can safely remove the line from your program. return 0; This is the return statement. Because main() is defined as returning an integer, the above statement will return a status to the calling process indicating normal program termination. } The closing brace, above, marks the end of function main Running, Saving and Compiling the Program Simply choose "New File" and type out the program coding. 20
Avinash Kumar Singh
After typing the code in the compiler, save the file by giving it some name. The "Save As" option will appear under the "File" menu. Give a name (for example: myfirstprg). Now the file is saved as first.cpp. All C++ source files are saved in *.cpp format. Just like *.bmp represents a bitmap file, *.cpp denotes a C++ (C Plus Plus) source file. In the compiler program there will be an option called ‘Compile’ in the menu bar. Select the compile option and the compiler will do its work. It will compile the program and in case there are any errors, the compiler will point out the line where the error was detected. Check whether the program has been typed exactly as given earlier. Even if a semi-colon is missing, it will lead to errors. If the compiler says no errors (or if the message "compiled successfully" appears), then you can go to the next stage: building the *.exe file.
*.exe file extension stands for executable files. A *.cpp file cannot be run directly on the computer. This has to be converted into a *.exe file and to do so select the "Make or Build exe" option in the compiler. The file ‘first.exe’ will be created. Now the program can be executed from the DOS prompt by typing ‘first’. But instead of running the program every time from DOS, it will be convenient to run the program from the compiler itself and check the output. In the compiler there will be another option called "Run". Just click on this and the program will run from the compiler itself (you needn’t switch back and forth between DOS and the compiler screen). What’s the problem? When first.cpp is executed from the compiler the program will ask the user to enter a character. Once a character has been entered, the program will return to the compiler screen. You won't see your output! It might appear as if there is some problem with the program. What happens is that the program displays the character on the screen, immediately terminates the program and returns to the compiler screen. This happens so fast that you can’t see the output being displayed. Modify your program as shown below:
21
Avinash Kumar Singh
Output of the program:
Only after a character is typed will the program move to the next instruction. In the above program, there is no statement other than return 0; after getch ( ). Hence program flow is as follows: Output: The program asks the user to enter a letter. The user enters a letter. Then the program displays the typed letter on the screen. The program will not quit at this point since there is a statement getch ( ). It will wait till the user types another character. When the user presses a character the program will quit. Type the above program, save and run it from the compiler. Some compilers have named the function getch( ) as _getch( ). This function also requires the header. In other compilers if a similar problem is encountered while displaying the result try using getchar( ); instead of getch( ); getchar( ) function doesn’t require the conio.h header file. If the compiler does not recognize getchar( ), then instead of adding any of the in-built functions, just add another line as follows: cin>>letter; at the end of the program just before return 0; The program flow will be the same as described earlier. 22
Avinash Kumar Singh
Elements of C++ Language Tokens The smallest unit in the program is called a token. C++ has the following tokens: C++ Character Set Character set is a set of valid characters that a language can recognize. A character represents any letter any letter, digit or any sign. The C++ has the following character set Letters: A-Z, a-z Digit: 0-9 Special symbol: Space + - * / ^ \ ( ) [ ] { } = != < > . ' " , $ ; : % ! & ? _ # <= >= @ White Spaces: Blank space, Horizontal tab , New line Other: C++ can process any of the 256 characters as data or as literals. Identifiers Identifiers are very important in C++ and are used in all programs. What is an identifier? In the previous program ‘check’ was declared as a character variable. The identifier in this case is ‘check’. Basically identifiers are names that are given to variables, constants or functions. In the previous program there are two identifiers: ‘check’ and ‘i’. C++ permits the use of a huge variety of names for identifiers like: test Test int_test var1 var123 c_b_f _var Almost any name you can think of can be used as an identifier but there are some restrictions. An identifier should not start with a number. The first character of an identifier should be an alphabet or an underscore ( _ ). After the first character, numbers can be used in the identifier. Remember the following: Never start an identifier with anything other than a letter or an underscore. It is better to use a letter than starting with underscores. Do not use keywords as identifiers (ex: do not name an identifier as int). Uppercase and Lowercase identifiers are different (Check is different from check). Be careful when using characters that look similar to each other. For example ‘1’ (the number one) and ‘l’ (the lowercase alphabet L) look alike. Use names that are easy to understand (if you are storing the salary of a person, name the variable as ‘salary’ instead of declaring it as ‘x’. Do not use very long names. Do not name many variables with similar names (avoid using identifiers like: count, counter, counting etc.). 23
Avinash Kumar Singh
Keywords Keywords are reserved words in C++ programming. They should not be used as identifiers and all keywords should be in lower case. The 63 keywords are tabulated below: asm class double false int protected sizeof throw unsigned
Auto bool Const const_cast Dynamic_castelse float for Long mutable Public register Static static_cast True Try Using virtual
break continue enum friend namespace reinterpret_cast struct typedef void
case default explicit goto new return switch typeid volatile
catch Delete Export If Operator Short Template typename wchar_t
char do extern inline private signed this union while
Literals & Constant Literals are data items that never change their value during a program run. C++ allows several kind of literal: (a) Integer constants Integer constants are the whole numbers without any fractional part. An integer constant must have at least one digit that must contain any decimal point. C++ allow 3 type of integer constants: Decimal( base 10) Octal (base 8) Hexadecimal( base 16 ) (b) Character constants A character constant is one or more characters enclosed in single quotes, as in 'z'. A character constant in C++ must contains one or more character and must be enclosed in single quotation marcs. (c) Floating Constants Floating constants are also called real constants. Real constants are the numbers having fractional part. These may be written in one of the two forms called fractional form or the exponent form. (d) String literals Multiple character constants can be dealt with in two ways in C++. If encoded in single quotes, these are treated as character constants and if encoded in double quotes, these are treated as string constants. A strin literals is a sequence of characters surrounded by double quotes.
24
Avinash Kumar Singh
Punctuators The following characters are used as punctuator in C++: Bracket [ ] Parenthesis ( ) Braces { } comma , Semicolon ; colon : Asterisk * Ellipsis ... Equal = Pound sign # Variables Variable represents named storage location, whose values can be manipulated during program run. variables are called symbolic variables because they are named. There are two values associated with a symbolic variable: Rvalue, its data value stored at some location in the memory. Lvalue, its location value that is the address in the memory at which its data value is stored.
rvalue of A = 10 lvalue of A = 1052
rvalue of C = 25 lvalue of C = 1055
Showing rvalue and lvalue of a variable Declaration of a variable To declare a variable this format is used Syntax: data type name; To declare a signed/unsigned variable place these modifiers before the data type. Example: signed int a; unsigned short b; here are three places where a variable can be declared: local, formal parameters and local.
25
Avinash Kumar Singh
Local Variables Variables declared within a function are called local variables. They are also sometimes called automatic variables. These variables can be used only within the block (or function) in which they are declared. A block starts with an opening curly brace and ends in a closing curly brace. A local variable is created upon entry into the block and destroyed when the program exits that block. For example: void test ( ) { int q; q = 2; } void test2 ( ) { int q; q = 5; }
// Start of block
// End of block // Start of another block
The two q's that We have declared in the two functions (test and test2) have no relationship with each other. Each q is known only within its own block (since it is a local variable). The main advantage is that a local variable cannot be accidentally altered from outside the block. Global Variables These variables are known throughout the program. They can be used by any part of the program and are not limited like local variables. They are declared outside the main function. #include int count; int main ( ) { ...... }
// count is a global variable
Global variables will take up more memory because the compiler has to always keep it in memory.Avoid using too many global variables. Use it only if the variable is going to be used by a number of functions. Data Type Data can be of many type e.g. character, integer, real, string etc. Any thing enclosed in single quotes represent character data. Data type are means to identify the type of data and associated operation of handling it. 26
Avinash Kumar Singh
C++ data types are of two types: Fundamental Data type & Derived Data Type Fundamental Data type Integer (int): An integer can contain only digits (numbers) from 0 to 9. Examples of integers are: 0 10 345 6789 -23 -600 It includes positive and negative numbers but the numbers have to be whole numbers. It does accept the decimal point. Hence the following numbers are not integer data types: 3.5 4.8 0.23 These numbers come under the second category (floating point type) and not under integers. How to declare a variable as belonging to the type integer? The syntax is: int variable-name; In C++ ‘qualifiers’ can be used to vary the range of fundamental data types. Qualifiers are only supplements to the basic data types and they cannot be used separately on their own. They work only with a basic (or fundamental) data type. The 4 qualifiers available in C++ are: Short Long Signed Unsigned When an integer is specified as signed, then automatically the most significant bit of the number is used as a sign bit (to denote the sign of the number). Hence it can be used if the programmer needs positive and negative number values for the variable. By declaring a variable as an integer, by default you can specify both positive and negative values. By default an integer is a signed integer. In other words, int variable-name; 27
Avinash Kumar Singh
is the same as signed int variable-name; In the second form, ‘signed’ is the qualifier and it is used to explicitly state that the variable is a signed integer. For an unsigned integer the syntax will be: unsigned int variable-name; An unsigned integer can hold a value up to 65,535 (a signed integer can hold only up to 32,767). Of course, in an unsigned integer you cannot assign a negative value. The range is from 0 to 65,535. To go beyond 65,535 and make use of both positive and negative values as well, the qualifier long should be used. long int variable-name; Long integers occupy 4 bytes of memory (32 bits). Remember, long int actually means signed long int (you can give positive and negative values). If you specify unsigned long int variable-name; you can only assign positive values to the variable. Thus, two qualifiers can be used together with a basic data type. What about the ‘short’ qualifier? Short integer is the same as a signed integer. It occupies two bytes and has the same range of positive and negative values as the normal integer case. int x; is usually the same as short int x; Compilers (depending on the operating system) will assume ‘int’ as a ‘long int’ or a ‘short int’. Turbo C++ (which is a DOS based compiler) will default to ‘short int’ when you specify a variable as type ‘int’. Programmers sometimes prefer to explicitly state what type of integer they want to use by making use of the ‘short’ and ‘long’ qualifiers. ‘short int’ always occupies only 2 bytes (irrespective of whether the OS is Windows or DOS) while a ‘long int’ always occupies 4 bytes.
28
Avinash Kumar Singh
Floating Types (float): Floating type data include integers as well as numbers with a decimal point. It can also have an exponent. Exponent means 10 to the power of some integer value (whole number). 20000 = 2 x 10^4 = 2e4 = 2E4. If you specify decimal numbers, floating point data type will store up to a precision of 6 digits after the decimal point. Suppose 0.1234567 is assigned to a floating-point variable, the actual value stored would be 0.123457 (it will round up to the sixth digit after the decimal place). Valid floating-point numbers are: 0.1276 1.23 1.0 10.2 2e5 (this will be typed in your code as 2e5) Do not use an exponent with a decimal point. For example: 2e2.2 is an invalid floating point because the exponent has to be an integer. Floating point numbers use 4 bytes of memory and has a much greater range than integers because of the use of exponents. They can have values up to 10^38 (in positive and negative direction). The same qualifiers used for an integer can be applied to floating point numbers as well. To declare a floating variable, the syntax is: float variable-name; Character (char): A character uses just one byte of memory. It can store any character present on the keyboard (includes alphabets and numbers). It can take numbers from 0 to 9 only. The following are valid characters: A B 3 a : ‘ / If the number 13 is entered as the value for a character, the program will only store 1 (i.e it will store the first character that it encounters and will discard the rest). A character is stored in one byte (as a binary number). Thus whatever the user enters is converted into a binary number using some character set to perform this conversion. Mostly all computers make use of the ASCII (American Standard Code for Information Interchange). 29
Avinash Kumar Singh
For example, according to the ASCII coding, the letter ‘A’ has a decimal value of 65 and the letter ‘a’ has a value of 97. The syntax to declare a variable which can hold a character is: char variable-name; Double (double): This is similar to the floating-point data type but it has an even greater range extending up to 10308. The syntax to declare a variable of type double is: double variable-name; Boolean Type (bool): This data type will only accept two values: true or false. In C++, ‘true’ and ‘false’ are keywords. Actually a value of true corresponds to 1 (or a non-zero value) and a value of false corresponds to 0.
Remember: The size of data types given above is a general case. Data type sizes depend on the operating system. So it may vary from system to system. Name Bytes* Description Range* char 1 character or integer 8 bits length. signed: -128 to 127 unsigned: 0 to 255 short 2 integer 16 bits length. signed: -32768 to 32767 unsigned: 0 to 65535 long 4 integer 32 bits length. signed:-2147483648 to 2147483647 unsigned: 0 to 4294967295 int * Integer. Its length traditionally depends on the length of the system's Word type, thus in MSDOS it is 16 bits long, whereas in 32 bit systems (like Windows 9x/2000/NT and systems that work under protected mode in x86 systems) it is 32 bits long (4 bytes). See short, long float 4 floating point number. 3.4e + / - 38 (7 digits) 30 Avinash Kumar Singh
double 8 double precision floating point number. 1.7e + / - 308 (15 digits) long double 10 long double precision floating point number. 1.2e + / - 4932 (19 digits) bool 1 Boolean value. It can take one of two values: true or false Note: this is a type recently added by the ANSI-C++ standard. Not all compilers support it. true or false Derived Data Type From the fundamental type other types can be derived by using the declaration operators. Some of the derived data types are: Arrays Array refers to the named list of finite number n of similar data elements Each of the data elements can be referenced respectively by a set of consecutive numbers, usually 0,1, 2, .... n. Array can be one dimensional, two dimensional or multi dimensional. Syntax: int a[10]; int b[10][10]; Function A function is a named party of the program that can be invoked from other parts of the program as often needed. Program Using a function to accept a number and return the cube of the number:
Output of the program: 31
Avinash Kumar Singh
Pointer A pointer is a variable that holds a memory address. This address is usually the location the location of another variable in memory. If one variable contains the address of another variable, is said to point to the second.
References A reference is an alternative name for an object. A reference variable provides an alias for a previously defined variable. C++ introduces a new data type called reference. You can think of them as if they were "aliases'' to "real'' variables or objects. As an alias cannot exist without its corresponding real part, you cannot define single references. The ampersand (&) is used to define a reference. For example: int ix; /* ix is "real" variable */ int &rx = ix; /* rx is "alias" for ix */ ix = 1; /* also rx == 1 */ rx = 2; /* also ix == 2 */ References can be used as function arguments and return values. This allows to pass parameters as reference or to return a "handle'' to a calculated variable or object. Constant The keyword const can be added to the declaration of an object to make that object a constant rather than variable. The general form of constant declaration is as follows: Syntax: const int a=50; 32
Avinash Kumar Singh
Constants can be classified based on their data type. The various types are: Numeric type constants (includes integers, floating-point etc.) Character Constants String Constants Numeric Constants Numeric constants consist of a series of digits. Integer constants can be written in different number systems: hexadecimal (base 16), octal (base 8) or in decimal (base 10). A decimal integer constant is any normal whole number (can consist of digits from 0 to 9): 2,34, 100, 900, 1456 etc. An octal integer constant can contain digits from 0 to 7 only and it should start with a zero (so that the computer will know it is an octal number). For example: 023, 0567, 0214 etc. A hexadecimal integer constant should start with 0x or 0X and can consist of digits from 0 to 9 and A to F (uppercase and lowercase letters are allowed). For example: 0x10, 0x1FF etc. Floating point constants will have the decimal point in the number. Character and String Constants Character constants are single characters enclosed within two single quotes (or between two apostrophes). For example: ‘a’ , ‘b’ , ‘x’ , ‘1’ , ‘A’ , ‘*’ A single character enclosed within single quotes is a character constant. All character constants will have an integer value (determined from the ASCII table). A C++ statement: char ch = ‘B’; will assign the character constant ‘B’ to the character variable ch. String constants consist of a series of characters enclosed within double quotes. For example: "hello" "This is a string" "x" Even "x" is a string because it is enclosed in double quotes. "x" is different from ‘x’ (this is a character constant). The reason is because "x" actually consists of ‘x’ and ‘\0’ (the null character which will be explained later). Structure A structure is a collection of data of different data types under one name. e.g. Struct employees { char Name[10]; 33
Avinash Kumar Singh
int Age; int Salary; }; Union It is a collection of data of different types sharing common memory space. e.g. Union item { int m; float x; char c; }; Enumerated Data types This data types gives us an opportunity to invent your own data type and define what values the variable of this data type can take. Example: enum colors { red, green, blue, cyan }; colors foreground, background; Here the declaration has two parts: The first part declare the data type and specifies its possible values. The second part declare variable of this data type. Now we can give the values to these variables: foreground=red; background=blue; But remember we can't use values that aren't in the original declaration. Thus, the following declaration cause error. foreground=yellow; Operator Operators are tokens that trigger some computation when applied to variables and other objects in an expression. List of operators: Assignment: = Increment and decrement: ++ (pre or post fix) and -- (pre or post fix) Arithmetic: +, -, *, / and % (integer remainder) 34
Avinash Kumar Singh
Relational: == (equality), != (inequality), <, >, <= and >= Boolean: && (and), || (or) and ! (not) Bitwise: & (and), | (or), ^ (xor), ~ (not), << (shift left) and >> (shift right) Compound assignation operators: +=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |= and some other important we also discuss. Assignation: The assignation operator serves to assign a value to a variable. a = 5; assigns the integer value 5 to variable a. The part at the left of the = operator is known as lvalue (left value) and the right one as rvalue (right value). lvalue must always be a variable whereas the right side can be either a constant, a variable, the result of an operation or any combination of them. It is necessary to emphasize that the assignation operation always takes place from right to left and never at the inverse. a = b; Increament and Decrement: Another example of saving language when writing code are the increase operator (++) and the decrease operator (--). They increase or reduce by 1 the value stored in a variable. They are equivalent to +=1 and to -=1, respectively. Thus: a++; a+=1; a=a+1; are all equivalent in its functionality: the three increase by 1 the value of a. The Increment and decrement operators are further categorized into pre increment or decrement operators and post increment or decrement operators. Notice the difference: Example 1 Example 2 B=3; A=++B; // A is 4, B is 4 B=3; A=B++; // A is 3, B is 4 In Example 1, B is increased before its value is copied to A. While in Example 2, the value of B is copied to A and B is later increased. Arithmetic operators: The five arithmetical operations supported by the language are: + addition - subtraction * multiplication / division 35
Avinash Kumar Singh
% module Operations of addition, subtraction, multiplication and division should not suppose an understanding challenge for you since they literally correspond with their respective mathematical operators. The only one that may not be known by you is the module, specified with the percentage sign (%). Module is the operation that gives the remainder of a division of two integer values. For example: if we write a = 11 % 3;, the variable a will contain 2 as the result since 2 is the remainder from dividing 11 between 3. Relational operators ( ==, !=, >, <, >=, <= ) In order to evaluate a comparison between two expressions we can use the Relational operators. As specified by the ANSI-C++ standard, the result of a relational operation is a bool value that can only be true or false, according to the result of the comparison. We may want to compare two expressions, for example, to know if they are equal or if one is greater than the other. Here is a list of the relational operators that can be performed in C++: == Equal != Different > Greater than < Less than >= Greater or equal than <= Less or equal than Here you have some examples: (7 == 5) would return false. (5 > 4) would return true. (3 != 2) would return true. (6 >= 6) would return true. (5 < 5) would return false. Logic operators Operator ! is equivalent to Boolean operation NOT, it has only one operand, located at its right, and the only thing that it does is to invert the value of it, producing false if its operand is true and true if its operand is false. It is like saying that it returns the opposite result of evaluating its operand. For example: !(5 == 5) returns false because the expression at its right (5 == 5) would be true. !(6 <= 4) returns true because (6 <= 4) would be false. !true returns false. !false returns true. Logic operators && and || are used when evaluating two expressions to obtain a single result. They correspond with Boolean logic operations AND and OR respectively. The result of them depends on the relation between its two operands: First Operand a Second Operand b result a && b result a || b true true true true true false false true 36
Avinash Kumar Singh
false true false true false false false false For example: ( (5 == 5) && (3 > 6) ) returns false ( true && false ). ( (5 == 5) || (3 > 6)) returns true ( true || false ). Bitwise Operators Bitwise operators modify variables considering the bits that represent the values that they store, that means, their binary representation. op asm Description & AND Logical AND | OR Logical OR ^ XOR Logical exclusive OR ~ NOT Complement to one (bit inversion) << SHL Shift Left >> SHR Shift Right Compound assignation operators A feature of assignation in C++ that contributes to its fame of sparing language when writing are the compound assignation operators (+=, -=, *= and /= among others), which allow to modify the value of a variable with one of the basic operators: value += increase; is equivalent to value = value + increase; a -= 5; is equivalent to a = a - 5; a /= b; is equivalent to a = a / b; price *= units + 1; is equivalent to price = price * (units + 1); Some other operator Conditional operator (?). The conditional operator evaluates an expression and returns a different value according to the evaluated expression, depending on whether it is true or false. Its format is: exp1? exp2 :exp3 if condition is true the expression will return result1, if not it will return result2. 7==5 ? 4 : 3 returns 3 since 7 is not equal to 5. 7==5+2 ? 4 : 3 returns 4 since 7 is equal to 5+2. 5>3 ? a : b returns a, since 5 is greater than 3. a>b ? a : b returns the greater one, a or b. Explicit type casting operators Type casting operators allows you to convert a datum of a given type to another. There are several ways to do this in C++, the most popular one, compatible with the C language is to precede the expression to be converted by the new type enclosed between parenthesis (): int i; 37 Avinash Kumar Singh
float f = 3.14; i = (int) f; The previous code converts the float number 3.14 to an integer value (3). Here, the type casting operator was (int). Another way to do the same thing in C++ is using the constructor form: preceding the expression to be converted by the type and enclosing the expression between parenthesis: i = int ( f ); Both ways of type casting are valid in C++. And additionally ANSI-C++ added new type casting operators more specific for object oriented programming. sizeof() This operator accepts one parameter, that can be either a variable type or a variable itself and returns the size in bytes of that type or object: a = sizeof (char); This will return 1 to a because char is a one byte long type. The value returned by sizeof is a constant, so it is always determined before program execution. Program to show the use of conditional operator:
Output of the program:
38
Avinash Kumar Singh
If statement1 evaluate true then the value of the whole statement is the value of statement2 otherwise the value of the whole statement is the value of statement3. Scope Resolution Operator: :: You can tell the compiler to use the global identifier rather than the local identifier by prefixing the identifier with ::, the scope resolution operator. :: identifier class-name :: identifier namespace :: identifier The identifier can be a variable or a function. If you have nested local scopes, the scope resolution operator does not provide access to identifiers in the next outermost scope. It provides access to only the global identifiers. Example: // Demonstrate scope resolution operator
Output of the program:
The example above has two variables named amount. The first is global and contains the value 123. The second is local to the main function. The scope resolution operator tells the compiler to use the global amount instead of the local one. Note: The Function of I/O Library - iostream.h 39
Avinash Kumar Singh
At lowest levels, files are implemented as stream of bytes. A stream is simply a sequence of bytes. Input and output operation are supported by the istream (input stream) and ostream (output stream) classes. iostream.h is a header file which defines all the input and output operators. Output operator cout << "C++ is a object oriented language "; The operator << is called the insertion or put to operator. It insert or sends the contents of the variable on its right to the object. on its left. In other words this operator is used to display the output on the screen. Program to show use of output operator:
Output of the program:
Input operator cin>>"Ebiz is world's largest MLM company"; is an input statement or causes the program to wait for the user to type in a number. The operator >> is known as a extraction to get from operator. It extracts or take the value from the key word and assign it to the variable on its right. In other words this operator is used to read a value from standard input. Program to show use of input operator: 40
Avinash Kumar Singh
Output of the program:
For storing the values a variable is used. A variable refers to a storage area whose contents can vary during processing. Priority of operators Priority of operators When making complex expressions with several operands, we may have some doubts about which operand is evaluated first and which later. For example: in this expression: a=5+7 %2 we may doubt if it really means: a = 5 + (7 % 2) with result 6, or a = (5 + 7) % 2 with result 0 The correct answer is the first of the two expressions, with a result of 6. There is an established order with the priority of each operator, and not only the arithmetic ones (those whose preference we may already know from mathematics) but for all the operators which can appear in C++. From greatest to lowest priority The priority order is as follows: Operators Precedence and Associatively
41
Avinash Kumar Singh
Associativity defines -in the case that there are several operators of the same priority level- which one must be evaluated first, the rightmost one or the leftmost one. All these precedence levels for operators can be manipulated or become more legible using parenthesis signs ( and ), as in this example: a = 5 + 7 % 2; might be written as: a = 5 + (7 % 2); or a = (5 + 7) % 2; according to the operation that we wanted to perform. So if you want to write a complicated expression and you are not sure of the precedence levels, always include parenthesis. It will probably also be more legible code. Memory Management Operators C uses malloc() and calloc() functions to allocate memory dynamically at run time. Similarly, it uses the function free() to free dynamically allocated memory. Although C++ supports these functions , it also defines two unary operators new and delete that perform the task of allocating and freeing the memory in a better and easier way. An object can be created by using new and destroyed by using delete as and when required. 42
Avinash Kumar Singh
The new operator can be used to create object of any type. It takes the following general term: Syntax pointer-variable = new data-type; Here, pointer-variable is a pointer of data-type. The new operator allocates sufficient memory to hold a data object of type data-type and returns the address of the object. Example p = new int; q = new float; If we want to free a dynamically allocated array , we must use the following form of delete: Syntax delete [size] pointer-variable The size specifies the number of elements in the array to be freed. The problem with this form is that the programmer should r remember the size of the array. Example delete [ ] p; will delete the entire array pointed to by p. Expression An expression is composed of one or more operations. The objects of the operations are referred to as operands. An expression in C++ is any valid combination of operators, constants, and variables. Type of expressions Arithmetic Expression Arithmetic expression can either be integer expression or real expression, some times a mixed expression can also be formed with a mixture of real and integer expression. Integer expression- int a=10, b=3, c=4, d=213; . a+b, a*d etc Real expression- float x=1.20, y=23.63, z=23.23; . x+y, x*z etc. Logical expression The expression that result into 0 or 1 are called logical expression. The logical expression are the combination of constants, variable and logical and relational operator. The following are the examples of valid logical expression: . x>y, (-y), (x-y) etc. C++ Escape Sequences Escape sequences are character constants that are usually used to format text. Here are the most common: Common Escape Sequences \a Bell \b Backspace 43
Avinash Kumar Singh
\f \n \r \t \v \' \" \\
Formfeed New Line Carriage Return Horizontal Tab Vertical Tab Single quote Double quote Backslash
Control Structure Statements are the instructions given to the computer to perform any kind of action, be it data movements, be it making decisions, or be in repeating action. Various statements provided in C++ : Selection statement The selection statement allow you to choose the set of instructions for execution depending upon an expression value. a) if-else statement: It shows that the condition is checked in if statement if it returns the value true then it execute the statements inside the braces. If it returns false value the automatically the statements in else condition are executed. Syntax if( expression ) { statements; } else { statement; } Program. b) Switch statements: C++ provides a multiple branch selection statements known as switch. This selection statement test the value of an expression against the value of the expression. Syntax switch( expression) { case 1: case 2: ............ } 44
Avinash Kumar Singh
Iteration statement The iteration statements allows a set of instructions to be performed repeatedly until a certain condition to be fulfilled. The iteration statements are also called looping statements. Some of the Iteration statement described here a) The for loop: The for loop is easiest to understand of the C++ loops. All its loop controls are gathered at one place. Syntax for( initialization, increment/decrement, termination condition) { ......... ...... } b) The While loop: The second Loop available in C++ is the while loop. The while loop is entry controlled loop. Syntax while( expression) { loop body } Jump statement The jump statement unconditionally transfer the program control within a function. C++ has four statements that perform an unconditional branch. a) The goto statement: The goto statement can transfer a program control any where in the program. The target destination of goto statement is marked by a label. Syntax goto label; : : label: b) The Break statement: The break statement enables a program to skip over part of the code. A break statement terminates the smallest enclosing while, do-while, for or switch statement. 45
Avinash Kumar Singh
Syntax for(;;) { break; } c) Continue statement: Continue is another statement like break but the difference is that it restart the loop again when this statement is encountered skipping the statements after the statement. Syntax for(;;) { ... continue; ... } d) Exit statement: Like break one can get out of the loop you can get out of the program by using a library function exit(). This function causes the program to terminate as soon as it encountered.
46
Avinash Kumar Singh
Functions Now that you should have learned about variables, loops, and if statements it is time to learn about functions. You should have an idea of their uses. Cout is an example of a function. In general, functions perform a number of pre-defined commands to accomplish something productive. Function is a group of statements within a single unit. Basically, it is a set of statements grouped together. You may wonder what use a function is? Or you may ask why not write the entire program within the main function itself? The reason is simple. Suppose, in your program, you have to repeat a certain procedure at different instances. Mean, a particular function has to be done in different parts of the program. You could keep typing the code in all the places (making the program larger in size) or you could make use of functions concept. All you need to do is define the function once. Wherever you need to perform the function you just need to call it (the call statement is just one line). The general syntax of a function is: Return data type
Function name
(arguments);
The return data type specifies what sort of data the function will return to the calling function. For example if return data type is int, then the function will return an integer value to the main or calling function. If the return data type is void, this means that the function does not return any value. Actually the above syntax is the syntax for function declaration. You'll soon learn about it. Just read on... There are three components of a function namely: Function Declaration or Prototyping Function definition and Function call. Function Declaration and Prototyping Functions that a programmer writes will generally require a prototype. Just like an blueprint, the prototype tells the compiler what the function will return, what the function will be called, as well as what arguments the function can be passed. Declaration means declaring something to the compiler. This tells the compiler that a function which looks like this is coming later on in the program. It is a statement which specifies the function name, argument types and return data type. Function declaration is done before the main function itself. 47
Avinash Kumar Singh
Syntax Return data type
Function name
(parameter);
Note that Function declaration should have a statement terminator. Function Definition & call Once the compiler knows that you have declared a function, it then needs the definition of that function. Defining a function means writing the statements that you want to group under that function. Hence the function definition contains the code (or statements of the function). The first line of the definition is the Declarator. Don’t confuse declaration with declarator. The declarator is very similar to the function declaration except it does not have the statement terminator. The declarator must agree with the declaration. It must have the same function name, and the same types of arguments in the same order and the same return type. The general syntax of the three components of a function are as follows: // Function declaration Return data_type function_name (data type of parameter1, data type of parameter2) int main ( ) { function _ name (arguments); // This is function call. It comes within the main function } // Funtion definition Return data_type function_name(arguments) // Function Declarator { Body of function; // Function Code } Perhaps you feel a bit vague about the concepts of function. Don’t worry. It should become clear with an example. Example: function to add two numbers.
48
Avinash Kumar Singh
Output of the program:
The above program is quite a simple example to illustrate the three components of a function. As you can see, we have first declared that a function of the return data type void, with name add and no arguments. Then comes, as usual, the main function. Remember: The compiler will always execute what you type in the main function. You can execute other functions by calling them within the main function. The compiler will run the main function. Since We just want to illustrate functions with a simple example, We haven’t written any code in the main function other than the function call. When the compiler reads the function call statement, it knows that you had already declared a function by the same name and argument type. So it goes on reading your program and comes to the function definition. In this you have written a set of statements to find the sum of two numbers. The compiler will execute these statements. After displaying the result (due to the cout keyword in the add function), the compiler will go back to the main function. It will then see whether you have written anything after the function call. In this program We haven’t mentioned anything, except the end of the program. 49
Avinash Kumar Singh
If you remember, We said that the function declaration will tell the compiler that a function by that name is coming up later on in the program. But there is a way to avoid writing the function declaration, i.e. there is no need to declare the function. If you do not declare the function then, the function definition must come before (precede) the function call. In example 1, the function call came before the function definition and hence we had to declare the function at the beginning. Let us consider the same program to add two numbers using a function called add with no arguments.
Example:
Output of the program:
As you can see, in the above program there is only one small change. We haven’t declared the function because We defined it before calling it. When the compiler reads the above program, it will first read the function definition. Argument Argument is a piece of data passed from program to function. Argument allows a function to operate with different values. The variables used within the function to hold argument values are called parameters. The data type in the function declaration and function call should be the same. Maybe it all sounds a bit hard to understand. Just read on. 50
Avinash Kumar Singh
Consider the following program to explain arguments. Again consider the program to add two given numbers but using function arguments. Example:
As you can see in the above program, We have used two parameters within the function ‘add’. The function definition comes before the function call and hence We have not declared the function. Up till this point, everything is the same. Now observe the Decelerator statement. The parameter specified is int var1, int var2 What this means is that in the function named add, var1 and var2 are integers that are used in the body of the function. In the body We have declared a third integer, namely int var3. var1 and var2 are added and stored in var3 using the statement: var3=var1 + var2; The last statement of the function add, is just to display the value of var3. Now the question might arise, what are the values of var1 and var2? A good question. To get an answer to that just read on. Next the compiler comes to the main function. So far the compiler has only read through the code. When it comes to the main function it will start performing. Two integers have been declared and defined as int num1 and int num2. The values of num1 and num2 are obtained from the user. After obtaining the values, you see the statement: add(num1,num2); As you know, add is the name of a function that has already been defined. So this statement is the function call. In the brackets, We have mentioned the two arguments namely num1 and num2. These two values have already been obtained from the user. The compiler then goes to the function definition of add. Over there we have mentioned 51
Avinash Kumar Singh
the arguments as int var1 and int var2. But remember that the data type of the argument is the same. Num1, num2 are integers and so also are var1 and var2. What the compiler does next is to assign the value of num1 to var1 and num2 to var2. Thus now, var1=num1 and var2=num2. The body of the function add is now executed. Hence, in the above program the arguments are passed from the program (which is the main function) to the function add. The variables used to hold the argument values are known as parameters. The function declarator in the function definition specifies both data type and name of parameters. In our example, the parameters were var1 and var2. Their data types was int (integer). 'num1' and 'num2' are the arguments passed to the function. If we had used the function declaration then it would have been as follows: void add (int, int); In the function declaration you don’t have to specify the parameters. Return Values of Function So far we have only seen functions with void as the return data type. In this section you will learn about what is the use of return data type and how it can be used. Return values are used in the function syntax and so far we have mentioned void as the return value of a function. Void means: no value is returned by the function. Return value, as the name suggests, is used to return some value. When a function completes its execution it can return a single value to the calling program. The syntax is: Return
variable;
When a function returns a value, the data type of the value must be specified in the function. Consider the following program that uses return value concept:
52
Avinash Kumar Singh
Output of the program:
In the above program the only statement of interest is sum = add(int num1, int num2); As you have already learnt, the right side of the equal sign is actually the function call. This is being assigned to a variable called sum. Hence, it can clearly be seen that the function add has to be executed and some value should be returned. This value is assigned to sum. As you can see, in the declarator instead of void we have mentioned int as return data type. This means that the function add will return (or give back) an integer quantity to the calling program (in this case the caller is main function). The calling program is the one that calls a function. In this case the main function calls the function add. When the compiler executes the add function, it knows that the add function has to return a value to the main function (because the return data type of add is int). Therefore, the sum of num1 and num2 will be returned to main. This will be assigned to sum. Earlier when the return data type was void, nothing was returned by the function. 53
Avinash Kumar Singh
You have to mention the return data type in the function declaration also. void main ( ) and int main ( ) Remember We said that void main ( ) is the same as writing: int main ( ) { ................. //program code return 0; } we'll now show you a little benefit of using int main( ). This isn't an actual benefit but We just want to show you the difference. For exact reasons as to why we use int main ( ) check out the next section. Consider the following program:
Output of the program:
54
Avinash Kumar Singh
What do you think happens when the user types 1 as the value of test? Simple since test is equal to 1, the compiler will go into the body of if. It will display You typed 1 on the screen. Then the compiler will return a value of 1. Generally a return value of a non-zero number is used when errors are encountered. You can't use this return value anywhere else. In other functions (functions other than main), you can make use of the return value. A return value of 0 indicates a normally terminated program. After returning the value, the program exits. This is the point to be noted. Which means that the compiler will not even read the remaining few lines and hence nothing else will display on the screen. The compiler will quit once an integer has been returned to main. On the other hand if you type anything other than 1 for test, the compiler will skip the if body, display the last statement and then return 0. The program gets terminated. Learn more in the next section. Better to use int main() We thought that since we have taken a discussion of void main and int main, we could now go one step further into the topic. Which one is better? Or which one should we use and why? Void is generally used to declare functions that do not return values. You might have had this question about where does main function return its value to? Generally, a return value has to be returned to the calling process. When you use int main ( ), the main function returns an integer to the operating system (since the OS is what calls the program and in turn the main function). So OS is the one that calls your main ( ) function. Returning a value from main ( ) is like an exit function. The value is returned to the operating system and the program ends. What will the OS do with your returned value? Actually, the OS never wants to know what you return. The program which started your program might need to know. In any OS, a program when running is called a "process". When booting up, the operating system starts the first process . Thereafter the first process starts other processes such as a shell (shell is just a program which reads commands from the user and converts it to system calls). So when you write a program and execute it in the shell, the shell starts your program. So now, the shell is the parent process of your program (and your program is the child of the shell); Now, in the same way, suppose you want one of your programs to load another program to do a particular job and you want to know just whether the job was successful or not, then the OS get the exit code of the child process and gives it to the parent process; just like returning from a function. 55
Avinash Kumar Singh
So it is a standard to give the exit code as '0' for a success and any non-zero integer for a error. When programming in C/C++ you can give this exit code when you return from the main function. So you've to declare main as 'int main()' to do that. If you declare it as 'void main( )' C++ wont allow you to set a value to be returned to your parent program. So the variable which should contain the return code will be filled by no one., which means that memory can be in any state (unpredictable). Hence you have no control on what value your parent process gets when your child program exits. In MSDOS the shell is called 'Command.com'. In Windows the shell is'explorer.exe'. Hence it's always better to use int main ( ) along with a return value at the end of the main ( ) function. A return value of zero indicates a normally terminated program. A non-zero value is used in case of errors. Of course this does not mean that a program written with void main ( ) won’t work; but it is better to avoid writing such programs:
Output of the program:
All the other programs that We have written so far have used void main ( ). They will all work if you use int main ( ) with a return value as done in the above example. We advise you to go on with int main ( ) rather than void main ( ) whenever you write C++ programs. Types of Functions There are two types of functions namely:
56
Avinash Kumar Singh
Library Functions The declaration of library function is in the header file specified at the beginning of the program. The definition is in a library file that is automatically linked to the program. Declaration and definition are not required. We will only call the function. Example: clrscr ( ). User Defined Functions Declaration and definition are part of the source file (*.cpp file). Function definition and declaration have to be written by us. Example of user defined function is the add function that we saw in the previous section. Pass by Value and Pass by Reference We have seen as to how to pass values to a function by making use of arguments. First let me make one concept clear. What is a parameter and what is an argument? Parameter is the variable that you declare within the function. Argument is the variable that you pass to a function. Pass By Value Example: void check ( int x ) {.................... } int main ( ) { ........................... int b = 10; check (b); ...................... } In this function, x is a parameter and b ( which is the value to be passed ) is the argument. In this case the value of b (i.e. the argument) is copied in x (i.e. the parameter). Hence the parameter is actually a copy of the argument. The function will operate only on the copy and not on the original. This method is known as PASS BY VALUE. So far we have dealt only with pass by value.
57
Avinash Kumar Singh
Output of the program:
You can see that the value of a is unchanged. The function square works only on the parameter (i.e. on x ). Pass By Reference In pass by reference method, the function will operate on the original variable itself. It doesn't work on a copy of the argument but works on the argument itself. Consider the same square function example We took in the previous section.
58
Avinash Kumar Singh
Output of the program:
As you can see the result will be that the value of a is 100. The idea is simple: the argument passed is the address of a. The parameter of square is a pointer pointing to type integer. The address of a is assigned to this pointer. Within the function We've written: *x = (*x) * (*x); *x is pointer variable we write '*' operator before any variable then it becomes a pointer variable.* when used before a pointer, will give the value stored at that particular address. Hence we find the product of a and store it in a itself. i.e. the value of 100 is stored in the address of a instead of 10 which was originally stored. This is a call-by-reference method which was used in C. In C++ there is a different approach. Of course you can use the above method, but C++ has its own way. Pass by Reference C++ style In C++ we make use of the reference parameter. All you need to do is put & before your function's parameter. Example: void square (& x) Whatever operation is done on x will actually affect the original calling argument. Basically x can be said to be an implicit pointer. The difference is that you needn't use *x to operate on the parameter. We'll show you with an example (the same square function example).
59
Avinash Kumar Singh
Output of the program:
The line x = x * x ; actually operates on a and not on a copy of a. Function Overloading Many functions can have the same name but they should have different number of arguments or the types of the arguments should be different. This is known as function overloading. Consider the example given below: // A Program to illustrate function overloading
Output of the program:
60
Avinash Kumar Singh
In the above program, at the starting itself, the compiler can see that there are three functions with the name of display. But the compiler is also clever enough to see the arguments of each of the three functions. Once it sees that the arguments are different, the compiler will consider the three functions to be different. Inline Functions There may be instances when you want to repeat a process more than once in a program. Well, you may think of going for the concept of functions. It’s fine as long as your function is a bit long. Suppose there are only one or two lines you want to repeat? Is it worthwhile going for a function? When our compiler friend sees a function call, the compiler has to save the present memory address and then go to a new memory address to access the function. This means it will take some time and also use some memory space. If a function is very small, then there is no need to go for branching to sub routines (i.e. there is no need for using another function). Instead, we can make use of the inline functions. Inline functions will simply substitute the lines into the main program where the function is called. Example:
Output of the program: 61
Avinash Kumar Singh
As you can see above, the inline function is very similar to a normal function. Only difference is that you have to mention the keyword inline before the function. When the compiler comes to the function call, it knows that mtocms is an inline function. So the compiler will insert the body of the function in place of the function call. After making the substitutions wherever the inline function has been called (in our program it is in only one place), the compiler will execute the program. The advantage is that the compiler doesn’t need to save its present memory address, go to the function’s memory address, execute the function and return back to the original address. Instead the code is brought into the main program. Thus time consumption can be reduced. Recursion This is another favorite topic in interviews and in question papers. What is recursion? Recursion comes from the word ‘to recur’ which means happening repeatedly over and over again. In programming we have recursive functions and they are functions that keep repeating themselves. How do they repeat themselves? Well, it’s like the function keeps calling itself till an end occurs. It might seem really funny to think of a function calling itself but this is what exactly happens. The best example for recursion is to calculate factorials. In the last program We wrote a function to find the factorial of a number using ‘for’ loop. We’ll now see how to do the same using recursion. Remember to read the program just like the compiler would read it; otherwise you’re bound to get confused.
62
Avinash Kumar Singh
Output of the program:
First of all, the function fact ( ) is the recursive function here. Why? Check out the function body and you’ll see that this function calls itself. So, let’s read through the function just like the compiler would. For understanding purpose, let’s assume that we want to find the factorial of 4. Now num=4 and n=4. The compiler enters into the recursive function and calculates value of ‘result’. result = 4* fact (3); what does fact(3) mean? ‘Fact’ is a function and hence the function is being called with a different argument value. The value returned by the function is ‘result’ (which is 4*fact(3)). But there is another function called in this returned value. So the program tries to calculate fact(3). When calculating fact(3), it again calculates the value of ‘result’. Now, result=3*fact(2); 63
Avinash Kumar Singh
This value is returned and your actual expression in the computer would be 4*3*fact(2). What next? Calculate fact(2) and this leads to: result=2*fact(1); Hence the expression in the computer will be 4*3*2*fact(1). The program calculates fact(1). When the value of ‘n’ is 1, we have specified an ‘if’ condition that says: return 1; Hence 1 is returned for fact (1) and the entire expression now is: 4*3*2*1 and the compiler produces the result by multiplying all the terms. If you don’t give the ‘if’ condition the recursive nature will never stop and it will lead to problems. Remember: When using recursive functions make sure that there is a way for the function to stop itself from infinitely repeating itself. Will it repeat infinitely? When using recursion there are chances for stack overflow. Stack is a special portion of memory where the computer stores temporary values. For example when a computer encounters a function call, it has to store the current location before going to the function. When the function is executed, the program will return back to the original position and continue the program execution. In recursive functions, there are chances for the stack getting used up quickly. That’s what is stack overflow. Anyway, there isn’t much advantage of using recursion but there may be some cases where you feel that recursion might make the coding easier. But be very careful while using recursion. Remember: Any C++ function can be made recursive. What about main( )? It is also a C++ function. Well, main ( ) is the one function which CANNOT be made recursive. Manipulators Manipulators are keywords that are used for doing something to change the way the output appears on the screen. They are only for presentation purpose; just to make your program output look better. One of the most commonly used manipulators is endl. This is used to end the line and leave the next line blank. endl is used along with cout. You cannot use endl separately. The iomanip.h header file is used to include the manipulators. Let's check out an example program:
64
Avinash Kumar Singh
Output of the program:
The above program will display the line Hi, this is a test program. After this line there is an endl. Hence the compiler will end the current line and leave the next line blank. The next cout statement is again endl. This means another line is left blank. The next statement starts with an endl. Hence a third line is left blank before printing the last sentence on the screen. Don't use double quotes on endl. The above program could be easily written as follows: cout<< "Hi, this is a test program"<
65
Avinash Kumar Singh
66
Avinash Kumar Singh
Object and Classes Object Objects are the 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. They may also represent user-defined data such as vectors, time and lists. Programming problem is analyzed in terms of objects and the nature of communication between them. Program objects should be chosen such that they match closely with the real-world objects. Objects take up space in the memory and have an associated address like a record in Pascal or a structure in C. When a program is executed, the objects interact by sending messages to one another. For example, if "customer" and "accountant" are two objects in a program, then the customer object may send message to the account object requesting for the bank balance. Each object contains data, and cod to manipulate the data. Objects can interact without having to know details of each other's data or code. It is sufficient to know the type of message accepted, and the type of response returned by the objects. Declaring an object:
Declaring Object: Every object has its own memory and can store different data. Objects maintain a copy of attributes of the class. Classes A class represents a group of similar objects. A class bears the same relationship to an object that a type does to a variable. The Class forms the basic for object oriented programming in C++. Any thing you want to encapsulate should be placed with in the class. A class is a user defined data type. Once defined it is used to define objects of that type. A class is template for an object and an object is an instance of a class. When 67
Avinash Kumar Singh
defining a class , we are creating a new abstract data type that can be treated like any other built-in data type. The body of the class is enclosed in the braces and terminated by semi-colon. The class body contains the declaration of variables and functions. These functions and variables are collectively called data members. Their are usually grouped under two sections, namely, private and public to denote which of the members are private and which of them are public. The keywords private and public are known as visibility levels. Note that these keywords are followed by colons. The class members that have been declared as private can be accessed only from within the class. On the other hand, public members can be accessed from outside the class also. The variables declared inside the class are known as data members and the functions are known as member functions.
Syntax of a class: Keyword class name of class { private : private data; public : public function; }; // End of class- make a note of the A class is declared by use of the key word class. Program to declare a class:
68
Avinash Kumar Singh
//Adding two numbers // This program can be written easily without using classes but want to illustrate concept of classes here
Output of the programs:
69
Avinash Kumar Singh
First of all, the name of the class is add. Under this class we have the three member data: num1, num2, num3. Note that all three are made private. This means that any object that is created under the class add, will have these three member data already in it. Next comes the public part. In public we define any function that we want to make use of. The function definition is done in the usual way. Remember: only functions belonging to the class can access the private members. We have made three functions for a simple operation of adding two numbers. If you go through the statements, you may feel that the same thing could have been put under one function itself. The answer yes. If you want, you do the adding of two numbers and displaying the result within one function itself. The three functions are called member functions, i.e. any object belonging to the class can make use of the member function. The input function which comes under public part is changed as follows: void input ( ) // input is a member function { cout<< “Input the two numbers”; cin>>num1>>num2; } and in the main function you can write: int main( ) { add a1, a2; // Defining two objects a1 and a2 under the same class add a1.input(x,y); // get the values for num1 and num2 for object a1 a1.sum( ) a1.display( ); // display sum of numbers entered for a1 a2.input(x,y); // get the values for num1 and num2 for object a2 a2.sum( ) a2.display( ); // display the sum of two numbers entered for a2 return 0; } Hence in the result of the above program, you will get two separate answers. One is the result of adding num1 and num2 of a1 and the other is the result of adding num1 and num2 of a2. Classes and Object Together Data Hiding is an important feature of object oriented programming. The mechanism of hiding data is to put them in a class and make it private. Thus this data is hidden and 70
Avinash Kumar Singh
safe from any accidental manipulations, i.e none of the functions can accidentally change the member data. Object is an instance of a class, i.e. only when you define an object for a class, will the compiler allocate memory for the object. Class has two parts in it: private and public. As the name suggests, whatever is in private cannot be accessed by any function outside the class. Usually, data is made private while the functions are made public. For the Data hiding feature, data should be made private. Class is just a template or a form of data. Template means that it doesn’t physically occupy any memory space. But when an object is defined, memory is allocated. Template can be compared to the plan of a building. When the plan is drawn, we have not yet allocated the area on land for construction. We only know about how the building structure will be. But when construction is started, the area has been allocated. Similarly, the compiler allocates memory space only when an object of the class is defined. A class on its own without any objects does not occupy any space. Syntax of a class: (Keyword) class name_of_class { private : private data; public : public function; }; // End of class- make a note of the terminator.
A program to demonstrate Classes
71
Avinash Kumar Singh
Output of the program:
First of all, the name of the class is add. Under this class we have the three member data: num1, num2, num3. Note that all three are made private. This means that any object that is created under the class add, will have these three member data already in it. Next comes the public part. In public we define any function that we want to make use of. The function definition is done in the usual way. Remember: only functions belonging to the class can access the private members. We have made three functions for a simple operation of adding two numbers. If you go through the statements, you may feel that the same thing could have been put under one function itself. The answer yes. If you want, you do the adding of two numbers and displaying the result within one function itself. The three functions are called member functions, i.e. any object belonging to the class can make use of the member function. Just read on if you don’t understand. add a1 ; is the first statement in the main function. This statement creates an object named a1 belonging to the class add. Then we get the value for two integers x and y. The next statement is a1.input (x,y); a1 is the name of the object, input is a member function with two arguments (two integer arguments). If you remember we defined the input function in the public part of the class. Then there is the dot operator. The dot operator comes in between the object name and the member function. It is used to access or invoke the function. By invoke, We mean executing the function. When the compiler sees the line a1.input (x,y); it knows this is a function call. It goes to the input function that has been defined. The value of x and y is passed on to the integers var1 and var2. Then the input function is executed. The input function just assigns the value of var1 (i.e. actually the value of x that the user entered) to the member data num1. Similarly it assigns var2 to num2, which is also a member data. All the member functions can make use of the member datas. The next line in main is a1.add( ); 72
Avinash Kumar Singh
This function has no arguments. So the the brackets are left empty. Again we are working with the same object a1. The add function is executed and finally the display function is also executed. You might be wondering what’s the use of the object a1? Why do we need it? Read on for answers: Just like a1 you can create another object called a2 under the same class add. This object will also have the same member datas and also the member functions. They can all be used in the same way as you used a1. If you are doing so, it would be advisable to make the following change: Put the statement to obtain the numbers from the user within the input function, rather than keeping it in the main function. The input function which comes under public part is changed as follows: void input ( ) // input is a member function { cout<< “Input the two numbers”; cin>>num1>>num2; } and in the main function you can write: int main( ) { add a1, a2; a1.input(x,y); a1.sum( ) a1.display( ); a2.input(x,y); a2.sum( ) a2.display( ); return 0; }
// Defining two objects a1 and a2 under the same class add // get the values for num1 and num2 for object a1 // display sum of numbers entered for a1 // get the values for num1 and num2 for object a2 // display the sum of two numbers entered for a2
Hence in the result of the above program, you will get two separate answers. One is the result of adding num1 and num2 of a1 and the other is the result of adding num1 and num2 of a2. Beware while using Classes We wanted to write this section to illustrate the most important concept of classes. We think after reading this section you will be quite clear about classes. A few points to remember while using classes are: 73
Avinash Kumar Singh
You cannot access private members of a class directly. Private members can only be accessed through the member functions (which have to be public). An object can directly call only public functions. Private ones cannot be accessed directly. Example: class add { private : int num1, num2, num3; // The member data has been made private public : void input (int var1, int var2) { num1 = var1; num2 = var2; } // ... you could have other member functions }; int main ( ) { add a1; // Creating an object a1 cout<<"Enter a value for num1"; cin>>a1.num1; // *** Error cannot run this program *** return 0; } The program will not run because of the code: a1.num1; a1 is an object of the class add. num1 is a private member of class add. Private members cannot be accessed directly by the object. Therefore, a1.num1 is an error. You can access num1 only through one of you public functions. Static Members We’ve already seen about the use of static. Now we shall see the use of static in classes. Before going into the topic We would like to restate that a class is just an empty area. No area is allocated when you create a class. So, only when you create an object of that class the compiler will allocate space to the object. Again, this means that: private: int x; does not allocate space for an integer x. When you create objects belonging to this class, required space is allocated for holding the integer. Each new object that you create 74
Avinash Kumar Singh
belonging to this class will have its own version of the integer ‘x’. The keyword ‘static’ helps you to create a single copy for all objects belonging to the same class.
Output of the program:
As you can see, the integer ‘count’ is declared to be static. But again outside the class we say: int bacteria::count=5; This is done so that the compiler will allocate space for the integer ‘count’. If ‘count’ were not static, when would the compiler allocate space to it? It would allocate space when an object is created. But in the case of static variable members in a class, we will create it only once and so we have to ensure that the compiler creates that one instance of the variable. In this case we’ve initialized it to a starting value of 5. If you type: int bacteria::count; count would be initialized with 0.
75
Avinash Kumar Singh
Since ‘count’ is static, each time you change the value of ‘count’, all the objects belonging to that class will make use of the new value. So far we’ve seen static member data but you can also make functions static in a class. Just precede the function by the keyword static. Static functions will be useful to operate on static member data Friend Function Remember We said that the private member datas of a class can be accessed only by the class' member functions. Well, there is one exception. We have what is called a friend function. As the name implies, a friend function will be friendly with a class even though it is not a member of that class. Perhaps we are confusing you a little. Don't worry, just check out the example below:
Output of the program:
we'll give you a little explanation so that you can understand the concept. First of all we've created a class named counter. It has one private data: count and one public function setvalue. It also has a friend function called getvalue. Then we've terminated the class. Next comes the definition of getvalue: int getvalue (counter x).......................Break up is as follows: int is the return data type. In this case we're returning an integer. The argument specifies an object. counter is the 76
Avinash Kumar Singh
class we've created and so x will be an object of counter. We define the function as: return x.count What the compiler will do is to return the value of count for the object you've created. In the main ( ) part, we've created an object called test whose count value is set to 6. Then we've called the friend function using getvalue(test).........This means, the compiler goes to the friend function getvalue, and uses the object test as the argument. So the value returned will be the count value of test (in other words it is test.count) and the result will be 6. What is to be remembered is: Friend functions are not members of any class. They can access private data of the class to which they are a friend. Since they are not members of any class, you should not call them using the dot operator. More on Friend Functions You might be wondering what's the big point of Friend Functions. We could have made getvalue as a member function of the class instead of declaring it as a friend function. What's the use? There are many uses, but the one We will deal with here is : being friendly to 2 or more classes. The friend function does not belong to any class, so it can be used to access private datas of two or more classes. we'll show you with an example:
77
Avinash Kumar Singh
Output of the program:
Just one thing to explain: In the second line of the program we've written: class counter2; This is a forward declaration of the class counter2. This is done because when the compiler reads through the lines in counter1 class, it encounters the word counter2 in the friend function. Uptil this point it doesn't know what counter2 is because we will be defining the counter2 class later on. So we tell the compiler in advance that counter2 is a 78
Avinash Kumar Singh
class by declaring it in the starting. If you don't declare it, you will get errors. Just check it out. One more note: You should declare the friend function in both the classes where you want it to be a friend. Command Line Arguments You know that functions can have arguments. You also know that main ( ) is a function. In this section we'll take a look at how to pass arguments to the main function. We are dealing with this topic now because what you pass will usually be filenames. First of all, let us suppose that we have a file by the name marks.cpp. From this file we make an exe file called marks.exe. This is an executable file and you can run it from the command prompt. The command prompt specifies what drive and directory you are currently in. The command prompt can be seen in the ms-dos prompt. C:\WINDOWS> This denotes that you are in C drive and in the directory of Windows. Your marks.exe program is in this directory(let us assume this). To run the program you will type: C:\WINDOWS> marks name result You must be thinking that we will type only the name of the program? In this case the C++ program that you wrote is assumed to have arguments for the main function as follows: int main (int argc, char * argv[ ] ) argc (the first argument-argument counter) stands for the number of arguments passed from the command line. argv (argument vector) is an array of character type that points to the command line arguments. In our example, the value of argc is 3 (marks, name, result). Hence for argv we have an array of 3 elements. They are: argv[0] which is marks argv[1] which is name argv[2] which is result Note: argv[0] will be the name that invokes the program (i.e. it is the name of the program that you have written). If you feel a little vague in this section don't worry. In the next section we'll take a look at a simple program. A program using Command Line Arguments We'll take a look at a program to demonstrate command line arguments. We shall start writing our programs in the proper C++ style with the new headers. In case the new style headers don't work in your compiler then you can use the old style. 79
Avinash Kumar Singh
The green colour indicates what you don't have to type (like the dos prompt). We've used green for the output as well. Red denotes (as usual) the code of the program as well as what you have to type.
Output of the program:
Save the file as test.cpp. Compile it and then make the executable file (test.exe). If you run test.exe from Windows (i.e. by just double clicking on the file), the output may just be as follows: The value of argument counter is 1 c:\windows\test.exe This will be the output since you didn't specify the arguments. To add the arguments you have to go to DOS prompt. From there type: c:\windows>test one two three You have to go to the folder in which you have the test.exe file. From that folder type the above line. The output would be as follows: The value of argument counter (argc) is 4 c:\windows\t.exe one two three Hope you understood how the command line arguments work. Objects being passed as Arguments Remember we discussed about pass by value and pass by reference methods in functions. If we don’t specify pass by reference then the compiler will actually work on a 80
Avinash Kumar Singh
copy of the original argument (and not directly on the argument itself). So, what happens when we pass objects? We saw the friend function earlier that has objects as it’s arguments. Does the function create a duplicate object and work on the new object or does it work on the real object that you passed? Check out the same program below:
Output of the program: 81
Avinash Kumar Singh
The first two lines appear because we create two objects: fever and cholera. The 3rd and 4th lines appear because that is what we ask the check ( ) function to do. In lines 5 to 8, we see that 2 bacteria objects and 2 virus objects are being destroyed. From where did the program create 2 bacteria and 2 viruses??? The answer lies in the fact that the function acts like the pass by value method. The function check ( ) creates a copy of the original arguments and works on these new objects that it created. But then why hasn’t the constructor been invoked two extra times? Remember that the function has to work on the exact copy of the original object. Constructors are usually used to initialize the member data. Thus, if the function invokes the constructors (it will initialize the member data), it will not be able to act on exact replicas of the original object. So, it does not invoke the constructor. But whatever has come into existence has to be destroyed and thus the 2 extra organisms are destroyed. There is a very important fact to be noted here. Usually we will specify the ‘delete’ keyword in the destructor to free up any memory that was taken up from the heap. When a function creates a copy of an object, it will copy the destructor also exactly as it is in the original object. Thus in the original object you will have a statement using ‘delete’, which will free up some particular memory space. The copied object will also have the same destructor and thus it will also ‘delete’ from the same memory area. You should never use the delete twice (We mean if you have one ‘new’, you should have only one ‘delete’). Double ‘delete’ can lead to serious errors. Thus the method of copying objects can sometimes lead to problems and for this purpose we have copy constructors (We’ll deal with them later).
82
Avinash Kumar Singh
Constructors and Destructors Constructors Basic Constructors You might remember that we can initialize a variable when declaring it. For example: int variable = 5; This line declares variable to be an integer and assigns the value of 5 to variable. Similarly, how about initializing an object? Constructors are used for this purpose. A constructor is a special member function with same name as the class. It is used for the automatic initialization of object and it is carried out at the time of creation. A constructor initializes an object immediately upon creation. It has same name as a class in which it resides and is syntactically similar to a function. Once created the constructor is automatically called after the object is created. Constructors have no return type. Syntax: constructor name (arguments): member data (value) {} As usual let's take a look at a simple program to illustrate the use of constructors. class counter { private: int count; public: counter ( ) : count (0) // Constructor initializes member data count to zero. {} .................................... // As usual you can write the public functions }; int main ( ) { counter c1; return 0; } When the compiler reads the line 83
Avinash Kumar Singh
counter c1; it goes to the public part of the class and sees the constructor used. Since counter c1; has no arguments the compiler makes use of the no argument constructor. In this case we have used only the no argument constructor. Hence the count of c1 is initialized to zero. This is what we wanted to do: Create an object and at the time of creation set the member data to a particular value. Instead of zero you can even give a value. For example: counter ( ) : count ( 7 ) {} If you use the above constructor, then the value of member data count is set to 7. Constructors with argument The constructors that can take arguments are called parameterized constructors. It's time to see constructors with arguments. They are similar to constructors without arguments. Example is shown below: class counter { private: int count; public: counter (int x) : count (x) {} .................................................// Some other functions in the class }; int main ( ) { int y; counter c1(2); cout<< "What value of count do you want initialize it to?"; cin>>y; counter c2(y); ......................................// We're not typing the rest. It could be anything to suit your purpose. return 0; } Program is simple. counter c1(2); means that the constructor with one argument is invoked. The argument passed is 2. Its value is assigned to count. count (x) is equal to count = x. Hence count of object c1 is two. counter c2 (y); means that count of c2 will be initialized to the value of y (i.e. the value the user types in). It also possible to define constructors with default argument. For example, the constructor count() can be declared as follows: 84
Avinash Kumar Singh
complex (float real, float imag=0); Dynamic Initialization of objects Classes objects can be initialized dynamically too. That is, the initial value of an object may be provided during run time. One advantage of dynamic initialization is that we can provide various initialization format, using overloaded constructors.
Copy Constructor A copy constructors is used to declare and initialize an object from another object. A copy constructor is invoked when you initialize a new object of a class using an existing object. This will happen when: You pass a copy of an object as argument to a function (i.e. when passing by value). When you return an object from a function Or initialize an object during declaration using another object. If we don’t specify a copy constructor, the compiler already has a default copy constructor. This default copy constructor will simply perform a bit-by-bit copy of the original object to the new object (i.e. it will blindly copy everything to the new object). As we saw earlier, this can lead to problems (especially when we use the ‘new’ and ‘delete’ operators in the constructor and destructor of the class). Let us suppose that we are using the ‘new’ operator in the constructor of the class and we have a function whose argument is an object of that class. While calling this function, we will pass an existing object to the function. The function will create a temporary object but it will not invoke the constructor for this new object. Hence the ‘new’ operator (present in the constructor) is not invoked and an exact replica of the passed object is made. During destruction, the temporary object will invoke the destructor (which has the ‘delete’ operator and it will delete the portion of memory allocated to the original object). When the original object is destroyed, it will also invoke the destructor and this will again try to free the same memory. This can lead to serious problems. To solve this problem we have to define our own copy constructor. Let ‘bacteria’ and ‘virus’ be two classes. Each one will have an array called ‘life’ created dynamically using the ‘new’ operator. We shall also define a friend function to which we will pass objects of both ‘bacteria’ and ‘virus’.
85
Avinash Kumar Singh
Output of the program:
Beware: The copy constructor will not work when you use the assignment operator (=) to assign one object to another. In such cases, you have to overload the = operator to avoid the problem (overloading is discussed in the next chapter). Dynamic Constructors 86
Avinash Kumar Singh
The constructors can also be used to allocate memory while creating objects. This will enable the system to allocate the right amount of memory for each object when the objects are not of the same size, thus resulting in the saving of memory. Allocation of memory to objects at the time of their construction is known as dynamic construction of objects. The memory is allocated with the help of the new operator. Here we are going to introduce the destructor which is often not necessary. You can use it to do some calculation whenever an instance is destroyed or output some text for debugging. But if variables of the instance point towards some allocated memory then the role of the destructor is essential: it must free that memory! Here is an example of such an application:
Output of the program:
87
Avinash Kumar Singh
Definition: The destructor is a member function that is invoked when an object goes out of scope. It should free any dynamically allocated memory that the object was using.
Destructors in Details Just as a constructor is used to initialize an object when it is created, a destructor is used to clean up the object just before it is destroyed. A destructor always has the same name as the class itself, but is preceded with a ~ symbol. Unlike constructors, a class may have at most one destructor. A destructor never takes any arguments and has no explicit return type. Destructors are generally useful for classes which have pointer data members which point to memory blocks allocated by the class itself. In such cases it is important to release member-allocated memory before the object is destroyed. A destructor can do just that. For example, our revised version of Set uses a dynamically-allocated array for the elems member. This memory should be released by a destructor as follows: class Set { public: Set (const int size); ~Set (void) {delete elems;} // destructor //... private: int *elems; // set elements int maxCard; // maximum cardinality int card; // set cardinality }; Now consider what happens when a Set is defined and used in a function: void Foo (void) { Set s(10); //... } 88
Avinash Kumar Singh
When Foo is called, the constructor for s is invoked, allocating storage for s.elems and initializing its data members. Next the rest of the body of Foo is executed. Finally, before Foo returns, the destructor for s is invoked, deleting the storage occupied by s.elems. Hence, as far as storage allocation is concerned, s behaves just like an automatic variable of a built-in type, which is created when its scope is entered and destroyed when its scope is left. In general, an object’s constructor is applied just before the object is destroyed. This in turn depends on the object’s scope. For example, a global object is destroyed when program execution is completed; an automatic object is destroyed when its scope is left; and a dynamic object is destroyed when the delete operator is applied to it. Implicit Member Argument When a class member function is called, it receives an implicit argument which denotes the particular object (of the class) for which the function is invoked. For example, in Point pt(10,20); pt.OffsetPt(2,2); pt is an implicit argument to OffsetPt. Within the body of the member function, one can refer to this implicit argument explicitly as this, which denotes a pointer to the object for which the member is invoked. Using this, OffsetPt can be rewritten as: Point::OffsetPt (int x, int y) { this->xVal += x; // equivalent to: xVal += x; this->yVal += y; // equivalent to: yVal += y; } Use of this in this particular example is redundant. There are, however, programming cases where the use of the this pointer is essential. We will see examples of such cases in Chapter 7, when discussing overloaded operators. The this pointer can be used for referring to member functions in exactly the same way as it is used for data members. It is important to bear in mind, however, that this is defined for use within member functions of a class only. In particular, it is undefined for global functions (including global friend functions). Scope Operator When calling a member function, we usually use an abbreviated syntax. For example: pt.OffsetPt(2,2); // abbreviated form This is equivalent to the full form: pt.Point::OffsetPt(2,2); // full form
89
Avinash Kumar Singh
The full form uses the binary scope operator :: to indicate that OffsetPt is a member of Point. In some situations, using the scope operator is essential. For example, the case where the name of a class member is hidden by a local variable (e.g., member function parameter) can be overcome using the scope operator: class Point { public: Point (int x, int y) { Point::x = x; Point::y = y; } //... private: int x, y; } Here x and y in the constructor (inner scope) hide x and y in the class (outer scope). The latter are referred to explicitly as Point::x and Point::y. Member Initialization List There are two ways of initializing the data members of a class. The first approach involves initializing the data members using assignments in the body of a constructor. For example: class Image { public: Image (const int w, const int h); private: int width; int height; //... }; Image::Image (const int w, const int h) { width = w; height = h; //... } The second approach uses a member initialization list in the definition of a constructor. For example: class Image { public: Image (const int w, const int h); private: int width; 90
Avinash Kumar Singh
int height; //... }; Image::Image (const int w, const int h) : width(w), height(h) { //... } The effect of this declaration is that width is initialized to w and height is initialized to h. The only difference between this approach and the previous one is that here members are initialized before the body of the constructor is executed. A member initialization list may be used for initializing any data member of a class. It is always placed between the constructor header and body. A colon is used to separate it from the header. It should consist of a comma-separated list of data members whose initial value appears within a pair of brackets. Constant Members A class data member may defined as constant. For example: class Image { const int width; const int height; //... }; However, data member constants cannot be initialized using the same syntax as for other constants: class Image { const int width = 256; // illegal initializer! const int height = 168; // illegal initializer! //... }; The correct way to initialize a data member constant is through a member initialization list: class Image { public: Image (const int w, const int h); private: const int width; const int height; //... }; 91
Avinash Kumar Singh
Image::Image (const int w, const int h) : width(w), height(h) { //... } As one would expect, no member function is allowed to assign to a constant data member. A constant data member is not appropriate for defining the dimension of an array data member. For example, in class Set { public: Set (void) : maxCard(10) { card = 0; } //... private: const maxCard; int elems[maxCard]; // illegal! int card; }; The array elems will be rejected by the compiler for not having a constant dimension. The reason for this being that maxCard is not bound to a value during compilation, but when the program is run and the constructor is invoked. Member functions may also be defined as constant. This is used to specify which member functions of a class may be invoked for a constant object. For example, class Set { public: Set (void) { card = 0; } Bool Member (const int) const; void AddElem (const int); //... }; Bool Set::Member (const int elem) const { //... } defines Member as a constant member function. To do so, the keyword const is inserted after the function header, both inside the class and in the function definition. A constant object can only be modified by the constant member functions of the class: const Set s; s.AddElem(10); // illegal: AddElem not a const member s.Member(10); // ok 92
Avinash Kumar Singh
Given that a constant member function is allowed to be invoked for constant objects, it would be illegal for it to attempt to modify any of the class data members. Constructors and destructors need never be defined as constant members, since they have permission to operate on constant objects. They are also exempted from the above rule and can assign to a data member of a constant object, unless the data member is itself a constant. Static Members A data member of a class can be defined to be static. This ensures that there will be exactly one copy of the member, shared by all objects of the class. For example, consider a Window class which represents windows on a bitmap display: class Window { static Window *first; // linked-list of all windows Window *next; // pointer to next window //... }; Here, no matter how many objects of type Window are defined, there will be only one instance of first. Like other static variables, a static data member is by default initialized to 0. It can be initialized to an arbitrary value in the same scope where the member function definitions appear: Window *Window::first = &myWindow; The alternative is to make such variables global, but this is exactly what static members are intended to avoid; by including the variable in a class, we can ensure that it will be inaccessible to anything outside the class. Member functions can also be defined to be static. Semantically, a static member function is like a global function which is a friend of the class, but inaccessible outside the class. It does not receive an implicit argument and hence cannot refer to this. Static member functions are useful for defining call-back routines whose parameter lists are predetermined and outside the control of the programmer. For example, the Window class might use a call-back function for repainting exposed areas of the window: class Window { //... static void PaintProc (Event *event); // call-back }; Because static members are shared and do not rely on the this pointer, they are best referred to using the class::member syntax. For example, first and PaintProc would be 93
Avinash Kumar Singh
referred to as Window::first and Window::PaintProc. Public static members can be referred to using this syntax by nonmember functions (e.g., global functions). Member Pointers As we have previously explained you how a function pointer is used to pass the address of a comparison function to a search function. It is possible to obtain and manipulate the address of a member function of a class in a similar fashion. As before, the idea is to make a function more flexible by making it independent of another function. The syntax for defining a pointer to a member function is slightly more complicated, since the class name must also be included in the function pointer type. For example: typedef int (Table::*Compare)(const char*, const char*); defines a member function pointer type called Compare for a class called Table. This type will match the address of any member function of Table which takes two constant character pointers and returns an int. Compare may be used for passing a pointer to a Search member of Table: class Table { public: Table (const int slots); int Search (char *item, Compare comp); int CaseSesitiveComp (const char*, const char*); int NormalizedComp (const char*, const char*); private: int slots; char **entries; }; The definition of Table includes two sample comparison member functions which can be passed to Search. Search has to use a slightly complicated syntax for invoking the comparison function via comp: int Table::Search (char *item, Compare comp) { int bot = 0; int top = slots - 1; int mid, cmp; while (bot <= top) { mid = (bot + top) / 2; if ((cmp = (this->*comp)(item, entries[mid])) == 0) return mid; // return item index else if (cmp < 0) top = mid - 1; // restrict search to lower half 94
Avinash Kumar Singh
else bot = mid + 1; // restrict search to upper half } return -1; // not found } Note that comp can only be invoked via a Table object (the this pointer is used in this case). None of the following attempts, though seemingly reasonable, will work: (*comp)(item, entries[mid]); // illegal: no class object! (Table::*comp)(item, entries[mid]); // illegal: no class object! this->*comp(item, entries[mid]); // illegal: need brackets! The last attempt will be interpreted as: this->*(comp(item, entries[mid])); // unintended precedence! Therefore the brackets around this->*comp are necessary. Using a Table object instead of this will require the following syntax: Table tab(10); (tab.*comp)(item, entries[mid]) Search can be called and passed either of the two comparison member functions of Table. For example: tab.Search("Sydney", Table::NormalizedComp); The address of a data member can be obtained using the same syntax as for a member function. For example: int Table::*n = &Table::slots; int m = this->*n; int p = tab.*n; The above class member pointer syntax applies to all members except for static. Static members are essentially global entities whose scope has been limited to a class. Pointers to static members use the conventional syntax of global entities. In general, the same protection rules apply as before: to take the address of a class member (data or function) one should have access to it. For example, a function which does not have access to the private members of a class cannot take the address of any of those members. References Members A class data member may defined as reference. For example: 95
Avinash Kumar Singh
class Image { int width; int height; int &widthRef; //... }; As with data member constants, a data member reference cannot be initialized using the same syntax as for other references: class Image { int width; int height; int &widthRef = width; // illegal! //... }; The correct way to initialize a data member reference is through a member initialization list: class Image { public: Image (const int w, const int h); private: int width; int height; int &widthRef; //... }; Image::Image (const int w, const int h) : widthRef(width) { //... } This causes widthRef to be a reference for width.
Class Object Members A data member of a class may be of a user-defined type, that is, an object of another class. For example, a Rectangle class may be defined using two Point data members which represent the top-left and bottom-right corners of the rectangle: class Rectangle { public: 96
Avinash Kumar Singh
Rectangle (int left, int top, int right, int bottom); //... private: Point topLeft; Point botRight; }; The constructor for Rectangle should also initialize the two object members of the class. Assuming that Point has a constructor, this is done by including topLeft and botRight in the member initialization list of the constructor for Rectangle: Rectangle::Rectangle (int left, int top, int right, int bottom) : topLeft(left,top), botRight(right,bottom) { } If the constructor for Point takes no parameters, or if it has default arguments for all of its parameters, then the above member initialization list may be omitted. Of course, the constructor is still implicitly called. The order of initialization is always as follows. First, the constructor for topLeft is invoked, followed by the constructor for botRight, and finally the constructor for Rectangle itself. Object destruction always follows the opposite direction. First the destructor for Rectangle (if any) is invoked, followed by the destructor for botRight, and finally for topLeft. The reason that topLeft is initialized before botRight is not that it appears first in the member initialization list, but because it appears before botRight in the class itself. Therefore, defining the constructor as follows would not change the initialization (or destruction) order: Rectangle::Rectangle (int left, int top, int right, int bottom) : botRight(right,bottom), topLeft(left,top) { }
Destructor is use to delete all the dynamic allocate memory. For example: //this is the destructor for a ragged array with a pointer to staff and staff have a pointer //to a char. First delete pointer to char, second delete pointer to staff, then delete node //destructor codes ragged::~ragged() { node *ptr; //while not end of the ragged array while(head!=NULL) //delete all the data 97
Avinash Kumar Singh
{ ptr=head->next; delete head->staff->string; delete head->staff; delete head; head=ptr; }
98
Avinash Kumar Singh
Operator Overloading and Type Conversion Operator Overloading This means giving additional meaning to normal operators when they are applied to user defined data types. The compiler identifies that it is an overloaded operator by looking at the data type of operand (i.e. if it is a user defined data type then the compiler knows it is an overloaded operator). You have to remember that objects are defined by you (We mean they are defined by the programmer). The data that comes under an object is chosen by you. The data type that you use will be in-built data type like integer or character but the object as a whole is user defined. Hence it is not possible to add two objects (that belong to the same class) using the + sign. But using operator overloading you could use the same + sign to add two objects. Syntax: return data type
keyword operator
sign of operator to be overloaded (arguments)
{ body of the function; } Example: void operator ++ ( ) { body of function; } Let us illustrate overloading by overloading an unary operator ( ++ ) class counter { private: int count; public: counter ( ) : count (0) // {}
Constructor that initializes count to zero
int display ( ) { return count; } 99
Avinash Kumar Singh
void operator ++ ( ) // ++ is overloaded operator. When compiler comes across ++ { // anywhere in the program, then if the operand is user defined, ++ count; // the compiler will do whatever is written within the body of the operator function } }; int main ( ) { counter c1, c2; cout<
// c1 and c2 are two objects belonging to class counter // count of c1 is 0 // count of c2 is 0 // ++ is an overloaded operator // Compiler knows this because c1 and c2 are objects-they are
// count of c1 is 1 // count of c2 is 2
When compiler comes across ++c1 it does the following. It knows that c1 is an object which a user defined data type. But ++ can operate only on in-built data types. Now it thinks. It remembers that ++ was already overloaded using the operator function within the class counter. So it goes back to the operator function and reads through what is written in the body. No return data type and no arguments. This makes it work a lot easier. ++count; count is an integer data type. The compiler increases the value of count by one and goes back to the original program. All this was done when it saw ++c1. Hence the count of c1 only is increased by one. When the compiler comes to ++c2 it increases the count of c2 by one. with return data type Consider the same example as in the previous section. This time we shall make use of the return data type in the operator function to return something to the main program.
100
Avinash Kumar Singh
In the above program we overload the same unary operator but use a return data type counter. Counter is the name of the class itself. This means the function is returning a class. But a class is just a template and means nothing without objects. Hence the function actually can be assumed to return an object ++count; return counter (count); As in the earlier program, the overloaded operator just increases the count by one. It does the same here. We know that counter is the name of the class. Within the braces we have written count. In the above example count of c1 was 0 and then it became 1 because of the ++count statement. Now count is 1. Hence the return statement will actually be counter (1). This line is just an object without a name (an unnamed object). The compiler remembers having seen the one argument constructor and goes to it. The count value of the unnamed object is initialised to one. The compiler remembers that all this is supposed to be returned. It goes back to the main program. c2 = ++c1; c2 is an object and hence the value of count of the unnamed object is stored in c2. So c2's count becomes 1. The above program illustrates the return data type. Suppose that you are using an enumeration and you wish to output its value: enum E {e = 37}; cout << e; 37 will indeed be output, by virtue of the enumerator value being promoted to an int and then output using the operator<<(int) function found in iostream.h.
101
Avinash Kumar Singh
But what if you're interested in actually seeing the enumerator values in symbolic form? One approach to this would be as follows:
Output of the program:
In the last output statement, we created an invalid enumerator value and then output it. Operator overloading in C++ is very powerful but can be abused. It's quite possible to create a system of operators such that it is difficult to know what is going on with a particular piece of code.
102
Avinash Kumar Singh
Some uses of overloaded operators, such as [] for array indexing with subscript checking, -> for smart pointers, or + - * / for doing arithmetic on complex numbers, can make sense, while other uses may not.
Binary Operator Overloading In the case of a unary operator we generally use no arguments. In the case of a binary operator we need to use one argument. Example:
Output of the program:
The above program is incomplete. This is just to illustrate overloading Let's take a closer look at the program. The values of feet and inches for dist1 are got from the user while dist2 is initialised to 11 feet and 6.25 inches. 103
Avinash Kumar Singh
The complier reads: dist3 = dist1 + dist2; What does it do? As usual it knows that + is overloaded and so it goes to the definition of the operator function. But we have a problem. + works on two operands, dist1 and dist2. So we need two values to be passed to the operator function so that it can add these two values. But the operator function has only one argument. Hence it is clear that only one of the values are passed ( i.e. only one object is passed). S, out of the two (dist1 and dist2) how do we know which one is passed? And what about the other value? Answer is simple. The operand to the right of the operator is passed as an argument. Hence the values of feet and inches of dist2 are passed to the operator function. Let's take a look at the first two lines within the operator function. int f = feet + d2.feet; float i = inches + d2.inches; First of all, you know that dist2 is passed as an argument. Hence, d2 actually represents dist2 in our case. f and i are two variables declared as integer and float respectively. In the expression : int f = feet + d2.feet; what does the feet stand for? This feet is the value of dist1's feet. dist1 is on the left of the operator and it is not passed as argument. Hence feet and inches refer to the values of dist1. In technical terms: When an overloaded operator is invoked, the object on the left of the operator is the object of which the operator is a member and the object on the right must be provided as argument to the operator. The rest of the program is just as normal. Overloading Binary Operator using Friends As we study earlier, friend function may be used in the place of member functions for overloading a binary operator. The only difference being that a friend function requires two argument to be explicitly passed to it while a member function requires only one. Here below given is the program which shows overloading operator using friends: The program overloads the operator * two times , thus overloading the operator function .operator*()itself.In both the cases, the function are explicitly passed two arguments and they are invoked like any other overloaded function, based on the types of its arguments. This enable us to both the forms of scalar multiplication such as p=2*m; //equivalent to p=operator*(2,m); q=n*2;//equivalent to q=operator*(n,2); The prog. and its output are largely self-explanatory. The first constructor vector(); constructs a vector whose elements are all zero. Thus vector m; creates a vector m ands initialize all its element to 0.The second operator-vector(int*x); 104
Avinash Kumar Singh
creates a vector and copies the elements pointed to by the pointer argument x into it. Therefore, the statements intx[3]={2,4,6}; vector n=x; creates n as a vector with components 2,4 and 6. Note that we have used vector variables like m and n in input and output statements just like simple variables. This has been made possible by overloading the operator >> and<< using the functions: friend istream & operator>>(istream &,vector&); friend ostream & operator<<(ostream &, vector &); istream ands ostream are classes defined in the iostream.h file which has been included in the program. Beware: There are some operator which can't be overloaded e.g.:- sizeof,.,.*,::,?: etc. Type Conversions Some types are automatically converted to other types as needed. For example, an integer value can always be used where a double value is expected. In the following: a := 5 b := a * .2 b is assigned the double value 1.0 and a's type remains integer. Similarly, a double value can be converted to a dcomplex value. Automatic conversions are limited to converting between numeric types, and converting a reference type to the type it refers to. Other types require explicit conversion. For example, the following expression is illegal: 5 * "1234foo" but the string can be explicitly converted to an integer using the function as_integer. The following yields an integer value of 6170: 5 * as_integer("1234foo") The following functions are available for explicit type conversion: as_boolean as_byte as_short as_integer as_float as_double as_complex as_dcomplex as_string There are types that cannot be converted at all. 105
Avinash Kumar Singh
For example, a function type cannot be converted to any other type. Type mismatches result in run-time errors. Type Conversion The following functions convert their argument to the stated type: as_boolean(x) as_byte(x) as_short(x) as_integer(x) as_float(x) as_double(x) as_complex(x) as_dcomplex(x) as_string(x) The argument x must be either numeric-or string-valued. See § 3.1.3, page , for a discussion of implicit type conversion (i.e., not requiring the use of one of these functions). Boolean Conversions Conversion of a numeric values to Boolean yield T if the converted value is non-zero. A string value yields T if its length is non-zero. For example: as_ boolean([3.14159, 0]) yields [T, F], and as_boolean("how are you?") yields [T, T, T], and as_boolean(['','a','']) yields [F, T, F], and as_boolean(".0000001") yields T, and as_boolean(".0000001foo") and as_boolean("0.") and as_boolean(0+9i) 106
Avinash Kumar Singh
yields T. Note that an empty string here means a string with no text in it; this is different from a string with no elements. as_boolean('') yields F, but as_boolean("") yields [], an empty (boolean) vector. Integer Conversions A boolean value converted to byte, short, or integer yields 1 if the value was T and 0 if F. Conversions between byte, short, and integer types yields the same values as the host machine's C++ compiler doing the same conversion via a cast. A float or double value yields the same integer value as the host machine's C++ compiler doing the same conversion via a cast. In particular, it is possible for a value like -3.14159 to be converted to -3 or -4 depending upon the particular compiler. If the direction of this conversion is important, you can use floor and ceiling: ceiling(x) returns the smallest integer which is greater than or equal to the argument, x. This function can be abbreviated as ceil. If x is a vector, ceiling is applied to each of the elements of the vector. floor(x) returns the largest integer which is less than or equal to the argument, x. If x is a vector, floor is applied to each of the elements of the vector. These will reliably convert floating point numbers to integers. complex or dcomplex values behave like float or double values except that complex or dcomplex values also lose their imaginary portion. A string value is converted as per the C (and C++) routine atoi(). If the value is not a valid integer then it is converted to 0. Float and Double Conversions A boolean value converted to float or double yields 1.0 if T and 0.0 if F. complex or dcomplex values lose their imaginary portion when converted to float or double. A string value is converted as per the C (and C++) routine atof(). If the value is not a valid floating-point number then it is converted to 0.0. 107
Avinash Kumar Singh
Complex Conversions A boolean value converted to complex or dcomplex yields 1.0+0.0i if T and 0.0+0.0i if F. float or double numbers converted to complex or dcomplex results in a complex number whose real portion is equal to the float or double value, and whose imaginary portion is 0.0. A string value is converted as per the C (and C++) routine atof(). String Conversions boolean values when converted to a string yields "T" if true and "F" if false. Byte, short, or integer values yield their natural string representation. float values are converted as per printf()'s "%.6g'' format. double values are converted as per printf()'s "%.12g'' format. complex values are converted as per printf()'s "%.6g+%.6gi'' format. dcomplex values are converted as per printf()'s "%.12g+%.12gi'' format. The conversion of floating point values to strings are changed by setting the system.print.precision value or the print.precision attribute for an individual value.
108
Avinash Kumar Singh
Inheritance Data Hiding It is also known as data encapsulation and is a fundamental concept of Object oriented programming. By the way, in many instances you may come across the term ‘method’. A method is just another term used for a function. Now let us assume that you have created a new library that you want to distribute to other programmers. A library is a C++ code written for some specific purpose. For example, working with images (bmp, gif or jpg) isn’t so easy in C++. You have to write methods (functions) for reading an image, identifying what type it is, displaying etc. There are many applications where image processing is applicable. The simplest application is in Optical Character Recognition (OCR). In OCR we try to write a program that will be able to recognize hand-written letters or numbers. For instance, if you write 8, the computer should be able to recognize that an 8 has been written (no matter how bad the handwriting is). Whatever you write on paper will be scanned into the system and stored in the form of an image file. A programmer developing an OCR application, could either start from scratch or he could focus on his problem (i.e. OCR). By starting from scratch, We mean that he has to write a lot of coding for reading an image etc. If he can get access to some good Image processing library he could simply use the #include directive and concentrate on the OCR algorithm. So, let’s say that you have created a library for the purpose of image processing. You will make use of the concept of classes. You will create a class called ‘Image’ which will contain member functions for reading an image, identifying the type of image etc. You will also have some member data like the height and width of the image. When you distribute your library to others, you give them the opportunity to create objects (or instances) of your ‘Image’ class. You will also have provided a little help file describing the various functions that are available for use. Note: You will only describe the use of the various functions (ex: the function syntax and what it will do). You will not be providing an insight into the implementation aspect of the function. Now, the OCR person will start coding for his application. There is a chance that he might use the same member data identifier ‘length’ and ‘width’ in his program. Imagine the consequence if ‘length’ and ‘width’ are not made private within the class. If they are not made private, there is a good chance that the user will fiddle around with the data (knowingly or unknowingly) and their values will get altered by the user (which is what you don’t want to happen). The result is that your functions, which operate on these member data, will produce some ambiguous results. By hiding your data, you prevent such problems from happening because the user will never be able to access or modify the member data. 109
Avinash Kumar Singh
Thus We would like to summarize the entire theory that We’ve dished out within a few lines to reinforce the concepts. Data encapsulation means hiding the implementation of a class from the user. We restrict the user in such a way that the user can perform only limited operations on the private data (and that is only through the member functions). Another advantage of hiding the implementation is that you (the class designer) may decide to change the algorithm used for reading an image. You might have discovered some better and effective method for doing the same purpose. By hiding the implementation, all you need to do is to change the function definition. The user will never have to change his code (because you have only changed the implementation, which the user has nothing to do with). The code written by the user will still run even though you have changed the implementation. Inheritance Inheritance means getting something from the parent. In C++ also, inheritance means the same. But who is the parent? Remember that classes and objects are a key feature in C++. When we talk of inheritance in C++, we talk of classes. We will have the parent class and the derived class. The derived class inherits all properties of the parent class. The parent class is known as the base class. All the classes that arise from the base class are known as derived classes. These derived classes inherit all non-private parts of the base class.When any data is made private in a class, it can be accessed ONLY by member functions of that class. A derived class CANNOT access the private area of its base class. Let's take a look at the syntax for making a derived class. Syntax The syntax is easy. Just create the base class as you normally would. Then when you want to create the derived class, just start with the following line: class d1 : public b1 { body of d1; }; where d1 is the name of the derived class and b1 is the name of the base class.
110
Avinash Kumar Singh
Output of the program:
We think you might have just one question. What's the meaning of protected? Well, as We said earlier, private data of a base class cannot be inherited by it's derived class. So the question arises as to how to make some data available to both the base and derived class? The answer is to make use of protected keyword. Protected data will be inherited by the derived classes. The rest of the program is as normal. Multiple Inheritance One important object-oriented mechanism is multiple inheritance. Multiple inheritance does not mean that multiple subclasses share the same superclass. It also does not mean that a subclass can inherit from a class which itself is a subclass of another class.
111
Avinash Kumar Singh
Multiple inheritance means that one subclass can have more than one superclass. This enables the subclass to inherit properties of more than one superclass and to "merge'' their properties. As an example consider again our drawing program. Suppose we already have a class String which allows convenient handling of text. For example, it might have a method to append other text. In our program we would like to use this class to add text to the possible drawing objects. It would be nice to also use already existing routines such as move() to move the text around. Consequently, it makes sense to let a drawable text have a point which defines its location within the drawing area. Therefore we derive a new class DrawableString which inherits properties from Point and String as illustrated in Figure below:
Definition (Multiple Inheritance) If class A inherits from more than one class, i.e.. A inherits from B1, B2, ..., Bn, we speak of multiple inheritance. This may introduce naming conflicts in A if at least two of its superclasses define properties with the same name. The above definition introduce naming conflicts which occur if more than one superclass of a subclass use the same name for either attributes or methods. For an example, let's assume, that class String defines a method setX() which sets the string to a sequence of "X'' character. The question arises, what should be inherited by DrawableString? The Point, String version or none of them? These conflicts can be solved in at least two ways: The order in which the superclasses are provided define which property will be accessible by the conflict causing name. Others will be "hidden''. The subclass must resolve the conflict by providing a property with the name and by defining how to use the ones from its superclasses. The first solution is not very convenient as it introduces implicit consequences depending on the order in which classes inherit from each other. For the second case, subclasses must explicitly redefine properties which are involved in a naming conflict. 112
Avinash Kumar Singh
A special type of naming conflict is introduced if a class D multiply inherits from superclasses Band C which themselves are derived from one superclass A. This leads to an inheritance graph as shown in Figure below: A name conflict introduced by a shared superclass of superclasses used with multiple inheritance.
The question arises what properties class D actually inherits from its superclasses B and C. Some existing programming languages solve this special inheritance graph by deriving D with the properties of A plus the properties of B and C without the properties they have inherited from A. Consequently, D cannot introduce naming conflicts with names of class A. However, if B and C add properties with the same name, D runs into a naming conflict. Another possible solution is, that D inherits from both inheritance paths. In this solution, D owns two copies of the properties of A: one is inherited by B and one by C. Although multiple inheritance is a powerful object-oriented mechanism the problems introduced with naming conflicts have lead several authors to "doom'' it. As the result of multiple inheritance can always be achieved by using (simple) inheritance some object-oriented languages even don't allow its use. However, carefully used, under some conditions multiple inheritance provides an efficient and elegant way of formulating things. There are some more types of inheritance is used in the nature of programming, some of them is given and discussed below:
113
Avinash Kumar Singh
Hierarchical Inheritance This is another interesting application of inheritance is to use it as a support to the hierarchical design of a program. In this type of approach many programming problems can be cast into a hierarchy where certain features of one level are shared by many others below that level. Hybrid Inheritance There could be the situations where we need to apply two or more types of inheritance to design a program. In this case we use Hybrid Inheritance.
114
Avinash Kumar Singh
Pointer, Virtual Functions and Polymorphism Address of a variable An introduction to pointers Pointers are variables that store memory address. This address is the address of another variable. You know that variables are stored in memory spaces. Memory spaces are bytes. For information, 8 bits make up one byte. Bits stands for Binary digits. A binary digit is a one or a zero. You have only one's and zeroes. You may remember that a character means it requires one byte, an integer two etc...... Every byte will have its own address. In computers the address is a hexadecimal number. For example: 0X8566fff4 is a hexadecimal number representing an address. Hence when we say that values of variables are stored in the computer, we actually mean that the value has been stored in a particular address. The 'address of ' operator is denoted by '&'. This can be applied to any variable as illustrated below:
Output of the program:
The concept of OOPs (Object Oriented Programming) makes emphasis on making decisions during run time rather than compile time. Run time is the time when someone runs your program. Compile time is the time at which you compile the program. Pointer Pointers are variables that store memory address. This address is the address of another variable. Hence a pointer points to another variable. 115 Avinash Kumar Singh
Declaring a Pointer: Syntax data type * name of pointer ; When * is used, it denotes a pointer. The data type denotes the data type to which the pointer points. Let's see an example: { int marks = 6; // marks is a variable value of integer type initialized to 6 int * pmarks; // pmarks is a pointer that points to an integer data type. pmarks = &marks; // pmarks is assigned the address of marks which is a integer. cout<< *pmarks; // Displays the value of 6. Explanation given below. cout<< pmarks; // Displays a memory address. } We think the above program (you have to write the usual void main and # include statements) is self explanatory. The only doubt you may have is what does cout<< *pmarks; do? In this context * is known as a dereferencing or indirect value operator. This operator will give the value stored at a particular location. It is the complement of the & operator that you saw in the previous section. Hence, *pmarks means value at pmarks (which holds an address). To summarize we can say that * means 'value at the address'. The two operators * and & can be considered as pointer operators. The difference between pointers and a general variable is that address is primary for pointers. The value stored at the address is secondary. For other variables, the value is primary while the address where the value is stored is secondary. The example below illustrates primary and secondary: { int x = 5; int * p; p = &x; cout<
// x is an integer // p is a pointer // p points to x // This displays the address. Hence address is primary for pointer
cout<<*p; // Only using * operator can we display the value. Hence value is secondary. cout<
Avinash Kumar Singh
} Be careful with Pointers This section deals with some of the mistakes that can be committed using pointers Note: Make sure that your pointer variable points to the correct type of data. If you declare a pointer of type int then make sure that the address it holds points to an integer. float y = 6.6; // y is a float quantity int * p; // p points to an integer type p = &y; // WRONG - p points to an integer but y is a float. Hence &y is address of a float. Thus the above part of a program is wrong. Suppose you want to declare two pointers: p1 and p2 that point to an integer data type. You might right the declaration as: int * p1, p2; Seems right, doesn't it? Well the declaration is WRONG. What this does is, declares p1 as a pointer pointing to integer type. The compiler will consider p2 as an integer and not a pointer. Since * precedes p1, the compiler knows that p1 is a pointer. Hence be careful while declaring pointers. Consider an extract from a program given below: long * marks; * marks = 223000;
// marks is a pointer that points to data type long. Statement correct. // WRONG
Note the point that we have not yet stored any memory address in marks. When a pointer is created the compiler will allot memory to hold an address. It will not allocate memory to hold data to which address points. Perhaps it's a bit confusing. Just read on... The problem with our program is that we are supposed to store an address in marks. After storing an address in marks you can then store some value at that address. What we have done is : we haven't assigned any address to marks. Hence the value 223000 cannot be placed anywhere. Pointers are not the same as integers. Pointers hold a memory address and hence they cannot be multiplied or divided. Regarding addition We shall discuss that later. Consider the following: int * p; p = 0xB8000000 ; 117
// Correct. Declaring a pointer that points to an integer. // WRONG Avinash Kumar Singh
We said that a pointer stores a memory address. So you may think that the second line is correct. We have assigned a hexadecimal number to p (which is a pointer). The problem is: the compiler doesn't know that 0xB8000000 is a memory address. You may get an error message saying data type mismatch. Instead you can write as: p = (int * ) 0xB8000000 ;
// This is correct.
Performing addition on Pointers We said that you can't perform multiplication and division on pointers. But you can do addition and subtraction on pointers. Suppose that p1 is a pointer that points to an integer and the address is 100 (yes, addresses should be hexadecimal numbers but assume 100 as a memory address for simplicity). Also assume that an integer occupies 2 bytes. Now we say: p1++ ; What would the above expression do? The value of p1 (i.e. the address of p1) gets changed. The address becomes 102 not 101 because an integer occupies 2 bytes. If an integer occupied 4 bytes then the result would be address 104. Similarly if you do: p1--; the address of p1 will be 98. Hence, when a pointer is incremented it points to the memory location of the next element of its data type. Similarly you could say the following: p1 = p1 + 10; This makes p1 point to the tenth element of p1's data type beyond the current position. If p1 points to a character type then p1 + 10 would move the pointer 10 bytes. Suppose p1 were a integer then p1 would move 20 bytes (if int occupies 2 bytes). Pointers and Arrays Arrays can be accessed using pointers instead of their index numbers. Consider the following program:
118
Avinash Kumar Singh
Output of the program:
When you say *(p + 1), the pointer adds one to itself (this means the pointer increments itself by the number of bytes of its data type). Hence it will go to the next integer address which is array[1]. The output will thus be 5. Consider a modification of the above program. The code is the same till array[2] = 6; After this line type in the following code: p = p+1; address cout<
// When pointer increments by one, it goes to the next integer // p now is having address of array[1]. Hence output is 5 // p is further increased by one. This now points to array[2].
this Pointer: Every C++ class has an implicit pointer called the this pointer. The this pointer points to the instantiation of the object. The this pointer can be de referenced to members of the class like any other pointer. Inside of a class declaration the use of the this pointer is implicit, so the code this->destroy(); is equivalent to destroy();
119
Avinash Kumar Singh
Polymorphism Poly means many. Polymorphism basically means many forms. As a simple example: there are many English words which have a different meaning depending on the context of use. Basically, the word is the same word but it's interpretation varies depending on the use. Similarly, in C++ we can make use of polymorphism. For example: consider operator overloading. You may have created an overloaded + operator to concatenate two strings. Now, the + sign can be used to add two strings (because you overloaded it) and it can even be used to add two numbers (which was it's actual use). Depending on the type of data being operated on, the compiler will decide on which function to use. If the operands are numbers, then it will use the normal function. This is a type of polymorphism. Therefore we have to distinguish different types of polymorphism which will be outlined here. The first type is similar to the concept of dynamic binding. Here, the type of a variable depends on its content. Thus, its type depends on the content at a specific time: v := 123 ... v := 'abc' ...
/* v is integer */ /* use v as integer */ /* v "switches" to string */ /* use v as string */
The concept of dynamic binding allows a variable to take different types dependent on the content at a particular time. This ability of a variable is called polymorphism. Another type of polymorphism can be defined for functions. For example, suppose you want to define a function isNull() which returns TRUE if its argument is 0 (zero) and FALSE otherwise. For integer numbers this is easy: boolean isNull(int i) { if (i == 0) then return TRUE else return FALSE endif } However, if we want to check this for real numbers, we should use another comparison due to the precision problem: boolean isNull(real r) { if (r < 0.01 and r > -0.99) then return TRUE else return FALSE endif 120
Avinash Kumar Singh
} In both cases we want the function to have the name isNull. In programming languages without polymorphism for functions we cannot declare these two functions because the name isNull would be doubly defined. Without polymorphism for functions, doubly defined names would be ambiguous. However, if the language would take the parameters of the function into account it would work. Thus, functions (or methods) are uniquely identified by: The name of the function (or method) and The types of its parameter list. Objects of superclasses can be filled with objects of their subclasses. Operators and methods of subclasses can be defined to be evaluated in two contexts: Based on object type, leading to an evaluation within the scope of the superclass. Based on object content, leading to an evaluation within the scope of the contained subclass. The second type is called polymorphism. Virtual Function Virtual function is a member function of a base class and redefined by a derived class. You need to make use of the keyword virtual, to create a virtual function. The redefined function in the derived class is done to meet the needs of the derived class. The main advantage of virtual function is that they support run-time polymorphism. Check out the example:
121
Avinash Kumar Singh
Output of the program:
In the starting We've created three classes: base (which is our base class), der1 and der2 (these two are derived from base). The function made virtual is the display ( ) function. Notice that We use the virtual keyword only in the base's virtual function. The derived classes der1 and der2, redefine the display ( ) function. Now come to the main ( ) function. base *p; As you know this is how a pointer is created. Instead of creating a pointer to an integer (or character as we usually do), we're creating a pointer to point to base (which is a class). Hence you can say that p is pointing to an object of type base. A pointer which points to an object of the base class, can point to an object of a derived class. But the reverse is not possible.
122
Avinash Kumar Singh
Next comes: p = &b; This assigns the address of the object b (which is an object of base) to the pointer p. Remember that p is a pointer to base type and b is an object of base type. So there's no problem. Pointers can be used to invoke member functions. Invoking in this way is done by using the following operator: -> (it's a minus followed by greater than sign). Since p is pointing to an object of base, the display( ) function of base will be executed. Next comes: p = &d1; A pointer to object of base can point to an object of a derived class. d1 is an object of der1 (which is derived from base). Therefore, p can point to d1 and the address of d1 is now assigned to p. When the display ( ) function is now invoked using the pointer p, the compiler will run the derived class der1's version of display ( ). This decision of choosing which function to execute is made at run-time. Hence this is known as run-time polymorphism. Pure Virtual Function A while back someone asked me how to solve a particular problem, one where there are objects of two different class types, with a common member function interface, and a desire for the member functions to know which object type they are called with. One simple way of solving this problem looks like this:
Output of the program: 123
Avinash Kumar Singh
Class1 and Class2 have no derivation or inheritance relationship with each other. They are independent classes with a common base Using a base class pointer, we can call either f() member function, and up in the right place, with the f() that is called knowing what type of object it has been called on. In this simple example, Base is an abstract class, and Base::f() a pure virtual function (denoted by "= 0"). A class is abstract if it contains at least one pure virtual function. No instances of an abstract class may be created, nor may an abstract class be used as a function argument or return type. Abstract class pointers and references are always legal. Typically an abstract class is used just as in the example above, to serve as a base and allow for manipulation via pointers or references that actually refer to instances of derived types.
124
Avinash Kumar Singh
I/O Operation The fundamental concepts of I/O in C++ are those of streams, insertion, and extraction. An input stream is a source of characters; that is, it is an object from which characters can be obtained (extracted). An output stream is a sink for characters; that is, it is an object to which characters can be directed (inserted). (It is also possible to have bidirectional streams, which can both produce and consume characters.) This section explains the basics of performing C++ I/O. For more details, refer to your C++ programming manual. This section covers the following components of C++ I/O: Insertion and Extraction Explanation of streams Formatting I/O Using manipulators in streams I/O status handling. Insertion and Extraction Insertion is the operation of sending characters to a stream, expressed by the overloaded insertion operator << . Thus, the following statement sends the character 'x' to the stream cout: cout << `x'; Extraction is the operation of taking characters from a stream, expressed by the overloaded extraction operator >>. The following expression (where ch has type char) obtains a single character from the stream cin and stores it in ch. cin >> ch; Although streams produce or consume characters, insertion and extraction can be used with other types of data. For instance, in the following statements, the characters '1' , '2' , and '3' are inserted into the stream cout, after which characters are extracted from cin, interpreted as an integer, and the result is assigned to i: int i = 123; cout << i; cin >> i; Insertion and extraction can be overloaded for user-defined types as well. Consider the following code: class fraction { 125
Avinash Kumar Singh
int numer; unsigned denom; friend ostream& operator <<(ostream& os, fraction& f) { return os << f.numer << `/' << f.denom; }; }; These statements define an insertion operator for a user-defined fraction class, which can be used as conveniently and easily as insertion of characters or ints. Get and put pointers The definition of C++ stream I/O makes use of the concepts of the get pointer and the put pointer. The get pointer for a stream indicates the position in the stream from which characters are extracted. Similarly, the put pointer for a stream indicates the position in the stream where characters are inserted. Use of the insertion or extraction operator on a stream causes the appropriate pointer to move. Note that these are abstract pointers, referencing positions in the abstract sequence of characters associated with the stream, not C++ pointers addressing specific memory locations. You can use member functions of the various stream classes to move the get or put pointer without performing an extraction or insertion. For example, the fstream::seekoff() member function moves the get and put pointers for an fstream. The exact behavior of the get and put pointers for a stream depends on the type of stream. For example, for fstream objects, the get and put pointers are tied together. That is, any operation that moves one always moves the other. For strstream objects, the pointers are independent. That is, either pointer can be moved without affecting the other. The get and put pointers reference positions between the characters of the stream, not the characters themselves. For example, consider the following sequence of characters as a stream, with the positions of the get and put pointers as marked in Illustration of Get and Put Pointers: Illustration of Get and Put Pointers
In this example, the next character extracted from the stream is 'c', and the next character inserted into the stream replaces the 'r'. 126
Avinash Kumar Singh
Streams This section covers the basics of using streams, including explaining which streams are provided by the streams library, how the different streams classes are related, which member functions are available for use with streams, and how to create your own streams. Streams provided by the library The streams library provides four different kinds of streams: strstream where characters are read and written to areas in memory. fstream where characters are read and written to external files. stdiostream where characters are read and written to external files using the C standard I/O library. bsamstream where a bsambuf object is used for performing formatted file I/O. stdiostream objects should be used in programs that use the C standard I/O package as well as C++, to avoid interference between the two forms of I/O; on some implementations, fstreams provide better performance than stdiostreams when interaction with C I/O is not an issue. Other types of streams can be defined by derivation from the base classes iostream and streambuf. See Stream class hierarchy for more information on the relationships between these classes. Every C++ program begins execution with four defined streams. cin is a standard source of input. It reads input from the same place that stdin would have. cout is a stream to which program output can be written. It writes output to the same place stdout would have. cerr is a stream to which program error output can be written. It writes output to the same place stderr would have. clog is another error stream that can be more highly buffered than cerr. It also writes output to the same place stderr would have. To use these streams, you must include the header file iostream.h. 127
Avinash Kumar Singh
Additional streams can be created by the program as necessary. For more information, see Creating streams. Stream class hierarchy All the different stream classes are derived from two common base classes: ios and streambuf. class ios is a base class for the classes istream (an input stream), ostream (an output stream) and iostream (a bidirectional stream). You are more likely to use these classes as base classes than to use class ios directly. The streambuf class is a class that implements buffering for streams and controls the flushing of a full output buffer or the refilling of an empty input buffer. Four sets of stream classes are provided in the standard streams library: fstream, strstream, stdiostream, and bsamstream. Corresponding to each of these stream classes is a buffer class: filebuf, strstreambuf, stdiobuf, and bsambuf, implementing a form of buffering appropriate to each stream. Note that the stream classes are not derived from the buffering classes; rather, a stream object has an associated buffering object of the appropriate kind (for instance, an fstream object has an associated filebuf ), which can be accessed directly if necessary using the rdbuf() member function. Relationship between Stream Classes shows the inheritance relationships between the various classes. Relationship between Stream Classes
128
Avinash Kumar Singh
Stream member functions In addition to providing the insertion and extraction operations, the stream classes define a number of other member functions that can be more convenient than using insertion and extra ction directly. All these functions are discussed in some detail in the class descriptions later in this chapter. The following list briefly describes a few of the most useful member functions. get() and getline() allows extraction of characters from a stream until a delimiter (by default ' \n ') is encountered, possibly with a limit to the number of characters to be extracted. The get() and getline() functions behave similarly, except that getline() extracts the final delimiter and get() does not. read() extracts a fixed number of characters from a stream. read() is intended for use with binary data, whereas get() and getline() are usually more appropriate with text data. putback() allows a character extracted from a stream to be "pushed back," so that it will be extracted again the next time a character is required from the stream. write() inserts a number of characters into a stream. The null character is treated as any other character and therefore this function is suitable for inserting binary data. flush() immediately transmits any buffered characters. For a stream associated with a terminal file, this causes any buffered characters to be transmitted to the terminal. For a nonterminal file, calling flush() may not cause any characters to be immediately written, depending on the characteristics of the file. tie() ties one stream to another stream, so that whenever the first file's buffer is full or needs to be refilled, the tied file's buffer is flushed. The cin stream is automatically tied to cout, which means that cout 's buffer is flushed before characters are extracted from cin. If, as is usually the case, cin and cout are both terminal files, this assures that you see any buffered output messages before having to enter a response. Similarly, the cerr stream is tied to cout , so that if an error message is generated to cerr, any buffered output characters are written first. seekg() and seekp() are used to reposition a stream for input and output respectively. 129 Avinash Kumar Singh
tellg() and tellp() The member functions tellg() and tellp() are used to determine the read or write position for a stream. As with the seeking functions, the results of these functions are system-dependent.
Creating streams Streams are normally created by declaring them or by use of the new operator. Creating an fstream or stdiostream entails opening the external file that is to be the source or sink of characters. Creating a strstream entails specifying the area of storage that will serve as the source or sink of characters. For fstream, a stream constructor can be used to create a stream associated with a particular file, similar to the way the fopen function is used in C. For instance, the following declaration creates an output fstream object, dict, associated with the CMS file named DICT DATA: ofstream dict("cms:dict data"); Opening files When you create an fstream (or a stdiostream), you must usually provide a filename and an open mode. The open mode specifies the way in which the file is to be accessed. For an ifstream, the default open mode is ios::in, specifying input only; for an ofstream, the default open mode is ios::out, specifying output only. If you declare an fstream without specifying any arguments, a default constructor is called that creates an unopened fstream. An unopened stream can be opened by use of the member function open(), which accepts the same arguments as the constructor. Defining a strstream When you create a strstream, you must usually provide an area of memory and a length. Insertions to the stream store into the area of memory; extractions return successive characters from the area. When the array is full, no more characters can be inserted; when all characters have been extracted, the ios::eof flag is set for the stream. For an istrstream, the length argument to the constructor is optional; if you omit it, the end of the storage area is determined by scanning for an end-of-string delimiter (' \0 '). For a strstream that permits output, you can create a dynamic stream by using a constructor with no arguments. In this case, memory is allocated dynamically to hold inserted characters. When all characters have been inserted, you can use the member function str() to "freeze" the stream. This prevents further insertions into the stream and returns the address of the area where previously inserted characters have been stored. Formatting When a program inserts or extracts values other than single characters, such as integers or floating-point data, a number of different formatting options are available. 130
Avinash Kumar Singh
For instance, some applications might want to have an inserted unsigned int transmitted in decimal, while for other applications hexadecimal might be more appropriate. A similar issue is whether white space should be skipped on input before storing or interpreting characters from a stream. The member function setf() is provided to allow program control of such options. For instance, the following expression sets the default for the stream cout to hexadecimal, so that integral values written to cout will ordinarily be transmitted in hexadecimal: cout.setf(ios:hex, ios:basefield) The streams library provides several similar functions: width() sets the number of characters to display. fill() defines the fill character when there are fewer characters to insert than the width. precision() sets the number of significant digits to write for floating-point values. Manipulators Again Use of the setf(), width(), and similar member functions is very convenient if the same specifications are used for a large number of inserted items. If the formatting frequently changes, it is more convenient to use a manipulator. A manipulator is an object that can be an operand to the << or >> operator, but which modifies the state of the stream, rather than actually inserting or extracting any data. For instance, the manipulators hex and dec can be used to request hexadecimal or decimal printing of integral values. Thus, the following sequence can be used to write out the value of i in decimal and the value of x[i] in hexadecimal: cout << "i = " << dec << i << ", x[i] = " << hex << x[i]; Other manipulators include the following: ws flush endl ends
skips white space on input. flushes a stream's buffer. inserts a newline character and then flushes the stream's buffer. inserts an end-of-string character ( '\0' ).
It is possible to create user-defined manipulators in addition to the standard manipulators, but this is beyond the scope of this book. See class IOMANIP for examples of user-defined manipulators, or refer to the C++ Programming Language, Second Edition for a detailed discussion. 131
Avinash Kumar Singh
I/O Status Handling Associated with each stream is a set of flags indicating the I/O state of the stream. For example, the flag ios::eofbit indicates that no more characters can be extracted from a stream, and the flag ios::failbit indicates that some previous request failed. The I/O state flags can be tested by member functions; for example, cin.eof() tests whether more characters can be extracted from the standard input stream. The I/O state flags can be individually manipulated by using the clear() member function; for example, cout.clear(0) clears all the I/O state flags for the stream cout. For convenience, the '!' operator and the conversion to void* operator allow concise testing of a stream for any error. These operators allow you to use statements such as the following, which writes the results of the function nextline to the standard output stream until an error occurs: while(cout) cout << nextline(); Because an insertion or extraction always produces its stream argument as its result, this can be further abbreviated to the following statement: while(cout << nextline()); This form makes it more obvious that the loop might not terminate at all. Note that attempting to extract from a stream from which no more characters can be taken is considered a failure. Thus, you can use a loop such as the following to extract and process items from a stream until the stream is exhausted: while(cin >> datum) process(datum);
132
Avinash Kumar Singh
Working with files You might have heard of I/O. It stands for Input-Output. In this section we'll take a look at the C++ file system. C++ has one feature common to a data base that it can store the data permanently for future use. Data can be stored in files and files can be edited and can be opened a program for reading it. The files specific functions are not provided in iostream.h they are provided in a separate header file fstream.h stands for files stream. Streams revisit Using C++ you can access a device through an intermediate medium. The intermediate medium is called as stream. The device that you access is known as file. Don't mistake the term file as a normal computer file. A normal file (a text file or a word document) is referred to as disk file. In this case file takes a broader meaning. It includes disk files, tape drives, the terminal, printers and so on. C++ is designed to work with these devices. To work with them you have streams. You can access devices using streams. The point is: Each device is different. Each one is unique. The C++ file system transforms each device into a stream. All streams will behave similarly though they provide access to different devices (or files). Hence streams are mostly device-independent. The function used to write to a disk file can be used to write to a printer as well. Hence all streams are similar but files are not. Each stream is associated with a specific file by using the open operation. Once you open a file (not just disk file-could be a printer) information can be exchanged between the file and your c++ program. This exchange is done through streams. Opening and Closing a File We think you'll find this interesting. You'll learn how to access disk files in the following sections. First of all you have to make use of another header file: fstream.h This header file has a number of classes already defined within it. Some of them are ofstream, ifstream, fstream etc... To access a file you have to have a stream. Hence first we declare a stream. The stream will be an object of one of the classes in fstream. ifstream in; ofstream out; fstream inout;
// stream in created for input // stream out created for output // stream inout created for input and output
Once you've created a stream, you can use the open ( ) function to associate it to a disk file. The open ( ) function is a member of all the three classes. It can be used as follows: 133 Avinash Kumar Singh
out.open("text.txt") ; // Opens a file called text.txt for output. The file is opened using the stream out which was created earlier. Note: When you say that a file is opened for output, it actually means that now you can write data to the file. When a file is opened for input (using ifstream), the data in the file can be displayed on the screen. Suppose there was a file text.txt already. When using output stream (ofstream), the stream will create a new file text.txt. Whatever content was there in the original text.txt gets deleted and you can write new data to text.txt. The 3 classes (ofstream, ifstream, fstream) have a constructor function that makes it easier to open a file. Example: ofstream out("text.txt"); text.txt.
// This creates an object out for output and opens the file
This statement makes use of the constructor in the ofstream class. Ifstream and fstream also have the constructor. Closing a File The member function for closing is close ( ). Since you do all I/O through the stream, you have to close the stream as follows: out.close( ); // To close a stream-type the name of the stream followed by a dot and then close ( ). Actually you can link this to the object and classes concept. Out is an object and close is a member function of the ofstream class. Hence by saying out.close( ); you're actually calling the member function. Can Errors occur while opening a file? We'll repeat a point which We made in the previous section: When you open a file using ofstream (which means output), you can write data to the file. You could say it's an input to the file. Hence open for output means actually for input. When a file is opened for reading, you will make use of the ifstream as follows: ifstream. instream("test.txt");
// The file test.txt is opened for reading
When you want to read a file, it means that the file is already present in your directory. Hence if you try to open a file (that isn't present) for reading, what happens? 134
Avinash Kumar Singh
The answer is, it's an error. When you open a file for writing data, the stream will create the file even if it doesn't exist. But if you attempt to open a file for reading and it isn't present, then it is an error. Hence you can check whether an error has resulted in the open operation as follows: if ( ! instream ) { cout<< "The file cannot be opened"; } if ( ! instream ) stands for: if not instream (that means if instream not open) then do what is said in the body of the if statement. Writing to a Text File Reading and Writing to a file is very easy. First we shall take a look at writing:
<< is known as the insertion operator. It is used for output along with the keyword cout (console out). Hence cout<<"Hi"; would actually write the word Hi on your screen (output). In the above program, instead of writing on the screen, we want to write to a particular file. Perhaps now you understand why we create an output stream for actually writing to a file. So we create a stream out for output and open the file test.txt. out<<"First "<<1<
135
Avinash Kumar Singh
>> is the extraction operator. As you know, it is used for obtaining an input from the keyboard along with the keyword cin (console in). Suppose you declare an integer x. You get the value from the user using the statement: cin>> x ; What the user types is stored in the variable x. Similarly in the above program what does the line in>>string>>num ; do? It reads from the stream in and stores what it read in the variable string and num. The process is as follows: First of all, the file has been opened. String is a character array. The compiler reads the file (test.txt which has been opened). It reads the first 15 characters. The first word in the file is First. After this it encounters a blank space. Hence the string is terminated (for details on why it doesn't continue reading check the section: Beware of character arrays). Hence the word First is stored in variable array string. Next comes a number. This gets stored in the variable num that you have declared. Next statement is: cout<>string>>num ; the compiler will read the next line of the file. The process just repeats and Second and 2 are now stored in string and num. Finally, the compiler prints the second line of the file on the screen. 136
Avinash Kumar Singh
Modes of Opening Files When you open a file (for writing or reading), there are 6 modes that you can use to specify how you want the file to be opened. The modes are: Modes of Opening Files Description ios::app causes all the output (or whatever you write) to be appended to the end of the file. This mode can be used only for files opened for output. ios::ate Go to the end of the opened file. ios::binary causes the file to be opened in binary mode (we'll deal with binary later on). ios::in specifies that the file is capable of input only. ios::out specifies that the file is capable of output. ios::trunc causes contents of pre-existing file by same name to be destroyed. So far we've seen the file opening as follows: ofstream out; out.open("test"); // This means test is opened in normal mode. By default this is the same as out.open("test", ios::out); // opened specifically for output We can combine two modes as follows: out.open("test", ios::out | ios::binary );
137
Avinash Kumar Singh
Template & Exception Handling Templates Templates are the mechanism that make it possible to use one function or class to handle many different data types. A template can be used to create the family of classes or functions. When templates used with the functions are called function templates, when they are used with the classes then they are called class templates. A template can also be considered as a kind of macro. When an object of a specific type is defined for actual use, the template definition for that class is substituted with the required data type. Since template is defined with a parameter that would be replaced by a specified data type at the time of actual use of the class or function, the templates are sometimes called parameterized classes or function. Function templates We can also define function templates that could be used to create a family of functions with different arguments types. The general format template is: template< class T > return-type functionname (arguments of type T) { //......... //Body of function //with type T //wherever appropriate //..... } Suppose you want to write a function that returns the minimum of two numbers. Ordinarily this function would be written for a particular data types. For example: int min (int a, int b) { return( a< b) ? a : b; } The following program shows how to write the min() functions a template, so that it will work with any standard type. we have invoked this function from main() for different data types. template T min( T a, T b) { return( a> b ) ? : b ; 138
Avinash Kumar Singh
} void main() { int i = 10, j = 20 ; cout << endl << min(i, j) char ch = 'A' , dh = 'Z'; double d=1.1, e=1.11; cout< return-type function-name ( arguments of types T1, T2, ....) { ...................... ...................... ...................... } Example:
139
Avinash Kumar Singh
Output of the program:
Function Template Overloading A template function may be overloaded either by templates or ordinary functions of its name. In such cases, the overloading resolution is accomplished as follows: Call an ordinary function that has an exact match. Call a template function that could be created with an exact match. Try normal overloading resolution to ordinary functions and call the one that matches. Member Function Templates When we created a class template for vector, all the member functions were defined as inline which was not necessary. We could have defined them outside the class as well. But remember that the member functions of the template classes themselves are parameterized by the type argument (to their template classes) and therefore these functions must be defined by the function templates. It takes the following general form: template < class T > return-type classname :: functionname (arglist) { //.............. //function body //................. } Example: //class template ....................... template < class T > class < class T > class vector { T* , v; int size; public: vector ( int m); vector ( T*, a); T operator* (vector & y); 140
Avinash Kumar Singh
}; //Member function templates............. template < class T > vector :: vector (int m); { v= new T [size = m]; for(int i = 0 ; i < size ; i++) v[i]=0; } template < class T > vector :: vector(T* a) { for(int i = 0 ; i < size ; i++) v [i] = a[i]; } template < class T > T vector < T > :: operator*(vector & y) { T sum = 0; for(int i = 0; i < size; i++) sum += this -> v[i] * y.v[i]; return sum; } Class Templates The concept of templates can be extended even to classes. Class templates are usually used for data storage (container) classes. Stacks and linked lists, which we encountered in previous chapters, are examples of container classes. However, the examples of these classes that we presented could store data of type float in a stack we would be required to define a completely new class. It follows that for every new data type that we wish to store , a new stack class would have to be created. Won't it be nice if we are able to write a single class specification that would work for variables of all types, instead of a single basic type. Enter class templates. Here is a program with class template in action. It is simple process to create a class using a template with anonymous type. The general format is: template < class T > Class classname { //.................. //class member specification //whenever appropriate //.................. }; 141
Avinash Kumar Singh
Example: template < class T > class vector { T* v; int size; public: vector ( int m ) { v = new [size = m]; for ( int i = 0; i < size; i++) v [i] = 0; } vector (T* a) { for(int i = 0; i < size; i++) v[i] = a[i]; } T operator* (vector &y) { T sum = 0; for(int i = 0; i < size; i++) sum += this -> v[i] * y - v[i]; return sum; } }; Class template with multiple statements We can use more than one generic data type in a class template. They are declared as a comma-separated list within the template specification as shown below: template < class T1 , class T2, ........ > class classname { ................... ...................(body of the class) ................... };
142
Avinash Kumar Singh
Example: Output of the program:
Exception handling Check out whether your C++ compiler supports this feature (the older C++ compilers will not support exception handling). This feature is used for dealing with certain specific situations (these situations are not supposed to occur and if you don’t provide some way of dealing with them then your program could simply freeze when the conditions really occur). To implement exception handling, C++ provides us with three keywords: Try Catch Throw How does it work? First you try (execute) the coding and in case some special situation is encountered, then the program will throw an exception. The exception that is thrown, will be caught by catch. int main( ) { 143
Avinash Kumar Singh
float a,b; try { cout<<"\nEnter a number : "; cin>>a; cout<<"\nEnter the denominator : "; cin>>b; if (b= =0) { throw 0; } cout<<"\nResult of division : "<
Avinash Kumar Singh
The 3 consecutive dots imply that this catch block will catch anything that is thrown. Uncaught Exceptions This is an interesting topic. What will happen if We throw a string but We have programmed for catching only integers? This is what is called as an uncaught exception and if you try it out, your compiler will display the message: Abnormal Program Termination Actually, what the compiler does is that it executes a terminate ( ) function. The terminate ( ) function will call the abort ( ) function. Usually, if there is some problem with the exception handling, then the compiler would either go to terminate ( ) function or it would invoke the unexpected ( ) function. The unexpected ( ) function will call the terminate ( ) function. Hence, ultimately the program will abort through the abort ( ) function. You can create your own version of the terminate function (in other words, you can set the terminate function) using: set_terminate(your-function); For using this, you would need to make use of the header file. void myterminate( ) { cout<<"\nMy Terminate Function"; abort( ); } int main( ) { float a,b; try { set_terminate(myterminate); cout<<"\nEnter a number : "; cin>>a; cout<<"\nEnter the denominator : "; cin>>b; if (b= =0) { throw "zero"; } cout<<"\nResult of division : "<
Avinash Kumar Singh
catch(int i) { cout<<"\nError - You entered : "< also defines some standard exceptions that are thrown. For example: bad_alloc- thrown if some problem is encountered using ‘new’ bad_exception- thrown when exception doesn't match any catch
146
Avinash Kumar Singh