Sei sulla pagina 1di 196

The Basic Language

1. The basic reason for the change in programming methodologies is the increasing complexity of programs.
2. OOP took the best ideas of structured programming and combined them with several new concepts. ` 3. What is an object? Objects are basic run time entities (real life entities) such as an invoice, a car etc.. It can also be defined as an entity able to save a state (info) and which offers a number of operations (behaviour) to either examine or affect this state. Ex. Person 4. What is object orientation? It is a technique for system modeling. It offers a number of concepts

OOP concepts : The basic concepts which are common to all OOP Languages are:

Encapsulation: The wrapping of data and functions into a single unit is known as encapsulation. The single unit is called Class. Polymorphism: Means the ability to take more than one form Ex: Operation addition exhibiting different behavior in different instances.

Inheritance: It is the process by which an object of one class acquires the properties of objects of another class.
Inheritance is important bcoz it supports the concept of classification.

Without this classification each object should define all its characteristics explicitly.
The concept of Inheritance provides the idea of reusability.

Differences between Structured Programming and OOP

In St.P emphasis is on What is happening. In OOP emphasis is on Who is being affected.


Data move openly around the system. In St.P. In OOP the data and functions that operate on the data are tied together In St.P most fns share global data. In OOP data is hidden and cannot be accessed by external functions.

In St.P, Large programs are divided to smaller programs known as functions, In OOP they are divided into objects.
Sample C++ Program

An action is referred to as an expression, An expression terminated by a semicolon is referred to as a statement. A statement is the smallest independent unit in a C++ Program

Ex: int b_count = 0; b_count = b_s + b_o; cout << b_count;

Like C, C++ program is a collection of functions.

A first look at input/output #include <iostream.h> main() { cout<< C++ is an extension of C; } The above statement introduces 2 new features cout and <<

The identifier cout is a predefined object that represents the standard output stream in C++.
The standard output stream represents the screen.

The operator << is called the insertion or put-to operator.

It inserts the contents of the variable on its right to the object on its left.
The identifier cin is a predefined object that represents the standard input stream in C++. The standard input stream represents the keyboard. The operator >> is called the extraction or get-from operator.

It extracts the value from the keyboard and assigns it to the variable on its right .
The preprocessor directives #define, #ifdef and #endif

The preprocessor directive #define can be used to create compiletime flags.


There are two choices to do this

i) Simply tell the preprocessor that the flag is defined, without specifying a value: #define FLAG ii) or give it a value (which is the typical C way to define a constant): #define PI 3.14159 2. In either case, the label can now be tested by the preprocessor to see if it has been defined: #ifdef FLAG will yield a true result, and the code following the #ifdef will be included in the package sent to the compiler. This inclusion stops when the preprocessor encounters the statement

#endif

or

#endif

// FLAG

3 4

Any non-comment after the #endif on the same line is illegal, even though some compilers may accept it. The complement of #define is #undef (short for un-define), which will make an #ifdef statement using the same variable yield a false result. #undef will also cause the preprocessor to stop using a macro. The complement of #ifdef is #ifndef, which will yield a true if the label has not been defined. (Used in header files) #ifndef HEADER_FLAG #define HEADER_FLAG

5 6

// Type declaration here...


#endif // HEADER_FLAG

A word about comments


1. C comments start with /* and end with */. It can include multiple lines. 2. C++ uses C-style comments and has an additional type of comment: //. 3. The // starts a comment that terminates at the end of the line. 4. It is more convenient for one-line comments, and is used extensively. For Ex: // This is a sample C++ program #include <iostream.h> main() { cout<< C++ is an extension of C; }

C++ Datatypes Pointer type: A Pointer is a variable which holds the address of another variable. A pointer is defined by prefixing the identifier with the dereference operator (*)

int *p = 0; //comment
int *p, ival; p = ival; //comment

A pointer can hold a value of zero, indicating that it points to no object. A pointer cannot hold a non address value. void *gp; Void pointer is called a generic pointer, which can hold the address value of any data type. But may not be dereferenced.

For Ex: void *gp; int *ip; gp = ip; // assign int pointer to void pointer But *ip = *gp; //illegal Pointer arithmetic: A number can be added to a pointer. A number can be subtracted from a pointer

A pointer when incremented always points to an immediate next location of its type.
String type: C++ provides two string representations:

i) C-style character string


ii) String Class type

The C-style originated within C language and is supported within C++ The string is stored within a character array and is manipulated thro a char* pointer. The C-style character string can be of zero length. String Class type : String class supports the following operations a) Initialize a string object both with a sequence of characters and with a second string object. b) Copy one string to another. c) Compare two strings for equality. d) To append two strings.

e) Finding String length.

f) Support to know whether a string is empty

g) Defining an empty string.


Const Qualifier: Const qualifier is used to prevent from accidental changes within a program.

Const double pi; //comment


Const cannot be modified after it is defined. Therefore it must be initialized.

const double wage = 9.6; double *ptr = &wage; //comment

The address of a constant object can be assigned only to a pointer to a constant object. double dval = 3.14; const double *pc = 0; const double wage = 9.6; pc = &wage; pc = &dval;

dval = 3.1415; *pc = 3.1415;

//comment

Here pointer is itself not a constant so we can reassign pointer to point to a different object but cannot modify the object pointer addresses. Int *const curerr = &errnum; int errnum = 0; *curerr = 5; //comment A constant pointer to non constant object can modify the value of the object but cannot change the address Const double pi = 3.14159; const double *const pi_ptr = &pi;

A constant pointer to a constant object can neither modify the value of the object nor the address itself can be changed.

Reference Types: A reference provides an alias for a previously defined object. The general form is: Data-type & reference-name = variable-name For Ex: float total = 100; float &sum = total; Both the variables refer to the same data object in the memory. Cout<<total<<\n<<sum; //Both print 100 total = total +10; // changes the value of both to 110 int &rerefval = &ival //comment

Although a reference serves as a pointer, it is not correct to initialize it to the address of an object

Once defined a reference cannot be made to refer to another object that is why it must be initialized. Each definition of a reference must be preceded by the address-of operator. int ival = 1024, ival1 = 2048; int &rval = ival, rval1 = ival2; //defines one reference int &rval = ival, &rval1 = ival2; // defines 2 references int ival = 1024, ival2 = 2048; int *pi = &ival, *pi2 = &ival2; pi = pi2; int &ri = ival, &ri2 = ival2; ri = ri2; The difference between a reference and a pointer is that a reference is internally treated as a constant pointer.

The major application of reference variables is in passing arguments to functions


void fun(int &x) { x = x+10; } main() { int m = 10; fun(m); //function call --------return 1; }

When the function call is executed , the following initialization occurs.


int &x = m;

Bool Type: A bool object can be assigned literal values true or false. For Ex: bool found = false;
short bool found = false; //comment Bool cannot be declared to be either signed, unsigned, short or long. bool found = false; int occ_count = 0; while( ) { found = look_for(); occ_count += found; }

Bool objects and Bool literals are implicitly promoted to type int when an arithmetic value is necessary. False becomes 0 and true 1.

Arithmetic and pointer values are implicitly converted to a value of type bool. For Ex: int find( int value );

int *find(int value);


if ( found = find(1024)) .. A zero or null pointer value is converted to false, all other values are converted to true

Enumerated Data type: It is a user-defined data type. The syntax of enum statement is similar to that of struct For Ex: enum shape{ circle, square, triangle}; The tag name becomes new type name and new variables can be declared using these tag names. For Ex: shape ellipse; Enum color {red, blue, green}; color bkground; color bkground = blue; color bkground = 7; //comment int c = red; //comment C++ does not permit an int value to be automatically converted to an enum value but an enum value can be used in place of an int value.

By default enumerators are assigned integer values starting with 0, 1, ..

Integer values can be assigned to enumerators explicitly. For Ex: enum color{red, blue = 4, green}
Anonymous enums are enums without tagnames. For Ex: enum {off, on}; int switch1 = off; Enumeration is used to define symbolic constants for a switch statement. { case circle: enum shape - - - - - - - break; {circle, rectangle, triangle}; case rectangle: Main() -- - - -; { int code; case triangle: cout<<Enter shape code:; -- - - -; cin>>code; cout<<Enter shape code:; While(code>=circle && code<=triangle) cin>>code; { switch(code) } }

Array Types: An array is a collection of objects of single data type.

For Ex: int a[10]; // declares an array of 10 ints

int staff_size = 27; const int buff_size = 512; int get_size(); char input_buffer[buf_size]; double salaries[staff_size]; int test_scores[get_size( )]; //comment The dimension must be a const expression. A non constant variable cannot be used to specify the dimension of an array. It must be possible to evaluate the value of the dimension at compile time. But the access to non-const object is accomplished only at run time and so it cannot be used as a dimension.

const int size = 5; int a[size] = {0, 1, 2};

int b[ ] = {1, 2, 3}

An array can be explicitly initialized and such an array need not specify a dimension value

If the dimension is greater than the number of elements, the non initialized elements are set to zero int a[5] = {0, 1, 2}; // a= {0, 1, 2, 0, 0}

A character array can be initialized as either a list of commaseparated characters or a string literal
const char ca1[ ] = {c, +, +}; const char ca2[ ] = C++ ; const char ch3[3] = C++ ;

The string const contains an additional terminating null character. int ia[ ] = {0, 1, 2}; int ia3[10]; int ia1[ ] = ia; ia3 = ia; //comment

An array cannot be initialized with another array, nor one array can be assigned to another.

int getindex( );

a[ getindex( ) ] = val;

Any expression that results in an integral value can be used to index into an array int *ap[ ] = {&ix, &jx, &kx }; int &ar[ ] = {&I, &j, &k}; An array of pointers is permitted but array of references is not permitted.

Complex Number Type: The complex number class is a part of standard library. To use it its associated header file <complex.h> must be included

Using this class it is possible to initialize one complex object with another Ex: complex <double> purei2(purei1);
An array of complex objects can be declared

Ex: complex <double> con[2] = { complex <double> (2, 3), complex <double> (2, 3) };
Complex numbers support addition, subtraction, multiplication, division and test for equality. Ex: complex <double> a; complex <double> b;

complex <double> c = a*b+a/b;

New and Delete : (Memory Management Operators)

These are the unary operators to perform dynamic memory allocation and de-allocation
New operator is used to create objects. The General Form is:

Pointer-variable = new data-type;


For Ex: int *p = new int; New operator can be used to initialize the memory Pointer-variable = new data-type(value); For Ex: int *p = new int(25); //value

The general form to create memory space for arrays


Pointer-variable = new data-type[size]; For Ex: int *p = new int[5]; //dimension

The general form of using delete delete pointer-variable; For Ex: delete p; To free dynamically allocated array delete [size] pointer-variable For Ex: delete [10] p; Recent version of C++ does not require the size to be specified delete [ ] p; If sufficient memory is not available for allocation, new returns a null pointer

FUNCTIONS

1. A Function is a self contained block of statements that performs a specific task 2. Operands of function definition Parameters 3. Operands of function call arguments

4. The function definition is composed of the function return type, the name of the function, the parameter list and the function body.
5. A function that does not return a value has a return type of void.

6. A function is evaluated whenever the functions name is followed by the call operator ( ) followed by a semicolon.

1. A function call can cause one of the two things to happen a. If the function has been declared inline, the body of the function may be expanded at the point of its call during compilation. b. Else the function is invoked at runtime and the control is transferred to the function being invoked. 2. When evaluation of the called function is complete, the suspended function resumes execution at the point immediately following the call. 3. A function must be declared bfore its called otherwise a compile time error results.

Function Prototype:

1. A function prototype consists of the function return type, the name of the function and the parameter list.
2. Need not specify name of the parameters Ex: int min(int,int)

3. A function prototype describes the functions interface(the number and type of parameters)
4. int[10] calc();

Array type cannot be specified as a return type.


5. Possible function return types int or double, int& or double* , enum or class or void

6. Function declarations are best placed within header files. The header files can be included in every file where functions are called

1. Const calc(double); //right or wrong


2. A function must specify a return type. Otherwise it results in compile-time error. Function parameter list(FPL) 1. FPL cannot be omitted. A function that does not have any parameters is represented either by an empty parameter list or a parameter list containing a single keyword void

2. Ex: int fun() or int fun(void)


3. int fun(int obj, float obj); 4. No two parameter names appearing in a parameter list can be the same.

Parameter type checking 1. Int gcd(int,int); gcd(hello, world); // comment gcd(243); // comment gcd(3.14,6.29); // comment 2. The function parameter list provides the compiler the necessary information to perform type checking. 3. Y a function cannot be called until it has first been declared. 4. In case of a type mismatch, an implicit conversion is applied. If an implicit conversion is not possible then a compile time error is issued.

Argument Passing: 1. Functions parameters are allocated storage on the programs run-time stack.

2. The storage remains associated with the function until the function terminates.
3. The storage size is determined by its type

4. The entire storage area of the function is referred to as Activation-Record.


5. Argument passing is the process of initializing the storage of function parameters. 6. Under pass-by-value, the local copies stored on run-time stack are manipulated, the contents of the arguments are not changed.

Situations where pass-by-value is not suitable


1. When large class objects are passed as arguments(time nd space costs to allocate memory are high.

2. When the values of the arguments must be modified.


Two Alternatives 1. To declare the parameters as pointers. 2. To declare the parameters to be references. Relationship betw Reference and a Parameter 1. A reference must be initialized and once initialized cannot be made to refer to another object. 2. A pointer can address a sequence of different objects or address no object at all 3. Reference parameters used in implementing overloaded parameters.

Default arguments:
1. Default arguments can be specified using initialization syntax with the parameter list 2. Ex: float amt(float principal, int time, float rate=0.15); 3. Functions providing default arguments can be invoked with or without an argument for this parameter. If an argument is provided it overloads the default argument value.

4. Arguments to the call are resolved by position.(cannot supply argument for time without supplying argument for principal)
5. Only the trailing arguments can have default values. We must add defaults from right to left 6. Ex: mul(int I, int j=5, int k=10); // comment 7. Mul(int I=15, int j, int k); //comment

1. A parameter can have its default argument specified only once in a file. Ex: // ff.h // ff.c int ff(int=0); #include ff.h int ff(int i=0) { }
2. By convention, the default argument is specified in the function declaration contained in the public header file. 3. A default argument can be any expression Ex: int set(int); int val;

int ff(int b=set(val), int c);


4. When the default argument is an expression, the expression is evaluated at the time the function is called.

State whether the following are right or wrong

1. Int ff(int a, int b, int c=0); // ff.h


2. #include ff.h Int ff(int a, int b, int c=0); 3. The above is an error bcoz it respecifies cs argument. 4. #include ff.h

int ff(int a, int b=0, int c);


5. The above is not an error it respecifies ff() to provide b with a default argument

Does the built-in printf() function provide the compiler the necessary information to perform type-checking.
Then how parameter type checking is performed???

Ellipses:

1. It is sometimes impossible to list the type and no. of all arguments that might be passed to a function. In these cases ellipses () can be specified in a function parameter list. 2. Ellipses suspend type-checking. Their presence tells the compiler that when the function is called, 0 or more arguments may follow and the types of the arguments are unknown.
3. Ellipses take either of the two forms void fun(param-list, ); void fun();

4. In first case, for arguments that correspond to parameters explicitly declared , type checking is performed and for arguments that correspond to ellipses, type checking is suspended.

1. Ex: int printf(const char* ); // first parameter is a character string

2. Every call of printf() be passed a first argument of type const char*


3. Whether arguments follow the character string is determined by the first argument

4. The format string % indicate the presence of additional arguments


5. Are the following two declarations equivalent? void fun(); void fun();

6. No they are not equivalent. First accepts no arguments, Second accepts 0 or more arguments 7. Fun(); // invokes which above function; 8. Fun(val); // invokes which above function;.

Returning a value:

1. There are two forms of return statements return; return(expression);


2. The first is primarily used to cause a premature termination of function, something similar to a break statement. 3. The second form of return statement provides the function result. It can be either a value or a reference

4. Return by Reference: int& max(int &x,int &y) { if(x>y) return x; else return y; }

1. Does any implicit return take place

Yes, upon completion of a functions final statement.


The function call max(a,b) = -1; // comment The above statement is legal and assigns 1 to a if it is larger, otherwise 1 to b

Array Parameters: 1. Arrays are never passed by value, rather is passed as a pointer to zeroth element 2. Void putvalues(int*); Void putvalues(int[]); Void putvalues(int[10]); 3. All the above three are equivalent declarations. 4. Passing an array as a pointer implies that the changes to an array parameter within the called function are made to the array argument itself and not to a local copy

1. . The size of an array is not part of its parameter type. 2. When the compiler applies parameter type checking on the argument type, there is no checking of the array sizes. . 3. Void putvalues(int[10]); void main() { int i ,j[2]; putvalues(&i); //comment putvalues(j); //comment }

4. Parameter type checking confirms that both calls of putvalues() provide an argument of type int*
5. Another mechanism is to declare the parameter as a reference to an array

1. void putvalues(int (&arr)[10]); void main() { int i ,j[2]; putvalues(i); //comment putvalues(j); //comment } 2. When the parameter is a reference to an array type, the array size becomes part of the parameter and argument types

3. The compiler checks that the size of the array argument matches the one specified in the function parameter type.
4. Void putvalues(const int[10]); // comment

5. Indicates that the function cannot change the array elements on declaring the elements in the parameter type as const

Linkage Directives: Extern c


1. If the programmer wishes to call a function written in another programming language, the compiler must be told about this. 2. The programmer does it using a Linkage Directive. 3. A Linkage directive can have one of the two forms. 4. Extern c void exit(int); // single statement form Extern c { int printf(const char* ); int scanf(const char* ); }//compound statement form 5. Though the function is written in another language, calls to it are fully type checked 6. Extern c { # include <cmath.h> } // comment

1. If a #include directive is enclosed within the braces of a compound statement LD, the linkage directive applies to all the declarations within the header file. 2. Int main() { extern c double sqrt(double); }
3. The above code results in a compile time error. A linkage directive cannot appear within a function body 4. A linkage directive is most appropriately placed within a header file.

Inline Functions

1. What is the objective of using functions in a program?


2. To save memory space. 3. State the disadvantage of functions. 4. When the function is small, substantial amount of execution time may be spent on overheads such as jumping to the function, pushing arguments into stack and returning to calling function.

5. One solution to this is to use macro definitions(preprocessor macros)


6. The drawback with macros is, error checking does not occur during compilation

7. C++ supports a new feature called inline functions


8. An inline function is a function that is expanded in line when it is invoked

1. The general form: 2. Inline function-header { function body } 3. Ex: inline int square(int a) { return a*a };

4. All inline functions must be defined bfore they are called


5. Inline keyword merely sends a request not a command to the compiler.

6. Compiler may ignore the request if the function definition is too long, and compile the function as a normal function.

Some situations where inline expansion may not work are:

For functions returning values, if a loop or a switch or a goto exists.


For functions not returning values, if a return statement exists If functions contain static variables.

If inline functions are recursive.

Recursion A function that calls itself is referred to as a recursive function. A recursive function must always define a stopping condition. Otherwise the function will recurse forever Ex: int factorial(int val) { if(val>1) return val * factorial(val-1); return 1; }

Overloaded Functions

1. Function overloading allows multiple functions that provide a common operation on different parameter types to share a common name
2. Ex: The expression 1 + 3 invokes the addition operation for integer operands and the expression 1.3 + 3.2 invokes the addition operation that handles floating point operands. 3. It is the job of the compiler to invoke the appropriate function.

Why overload a function name?


1. Function overloading relieves the programmer of lexical complexity of remembering each name occurring at the same scope referring to a unique entity. How to overload a function name? 1. 2 or more functions can be given the same name provided that each parameter list is unique either in number or type

2. When a function name is declared more than once in a particular scope, the compiler interprets the second declaration as follows. a) If the parameter lists of the functions differ either in number or type, the functions are considered to be overloaded. int max(int, int); float max(float, float, float); b) If both the return type and the parameter list of the function declarations match exactly, the second is treated as redeclaration. int max(int, int); int max(int, int); c) If the parameter lists of the function declarations match exactly, but the return types differ, the 2nd is treated as erroneous redeclaration. int max(int, int); float max(int, int); d) If the parameter lists of the functions differ only in default arguments, the second is treated as redeclaration.

int max(int, int); int max(int, int =10); 1. Typedef double Doll; extern Doll calc(Doll); extern double calc(double); 2. If of the function parameter lists, one uses typedef and the other uses the type to which the typedef corresponds, then the parameter lists are not different.

3. Typedef double Doll; extern Doll calc(Doll); extern int calc(double); 4. Void f(int); void f(const int);
5. The const and volatile qualifiers are not taken into account in identifying different functions

6. Void f(int*); void f(const int*); 7. Const or volatile qualifier is taken into account to identify the declarations if they are applied to a pointer or a reference.

8. Void f(int&); void f(const int&);


When not to overload a function name:

1. Whenever the different function names provide information that would make the program easier to understand For Ex: void setdate(Date&, int, int, int); void printdate(Const Date&); Date& convertdate(Const String&);
2. All of the above functions share the same datatype, namely class Date but do not share the same operation

Overloading and Scope

1. All the functions in a set of overloaded functions are declared in the same scope.
2. A locally declared function hides a function declared at global scope. void print(double); void print(const string&); // comment void fun(int val) { extern void print(int);// comment print(value:); // comment print(val); // comment }

1. A set of overloaded functions can also be declared within a class.


2. The functions that are members of distinct classes do not overload one another.

1. A set of overloaded functions can also be declared with in a namespace. Eg, namespace Development { extern void print (const char &); extern void print(const char &, int); } 2. The functions that are members of distinct namespaces do not overload one another.

3. Using declarations and using directives are mechanisms by which namespace members can be made visible in other scopes.
Extern C and overloaded functions

1. Can some functions in the overloaded set be C++ while other are C functions?
2. A Linkage Directive can be specified for only one function in a set of overloaded functions

For Ex: extern C void print(const char*); extern C void print(int); // error 3. Of the set of overloaded functions one is C function and the others are C++ functions. 4. The C function can be called from both C programs and C++ programs. 5. The additional functions can be called only from C++ programs. 6. The linkage directive does not influence the selection of a function for a function call. 7. For Ex: Class Emp{..}; Class stud{..}s1; extern c double cal(double); extern emp cal(const emp&); extern stud cal(const stud&); Int main() { cal(34); cal(s1); }

Pointers to Overloaded Functions

1. It is possible to declare a pointer to refer to a function in a set of overloaded functions.


2. How to initialize a pointer to a function <return type> <*fptr> (<parameter list>) <*fptr> = <&function name> 3. Extern void ff(long double); Extern void ff(int); Void (*pf1) (int) = &ff; Void (*pf2) (unsigned int) = &ff; 4. The compiler does not know which function to select by just looking at the initializer expression: &ff. 5. The compiler searches for the function in the overloaded set that has the same return type and the same parameter list as the pointers type.

6. Pf1 refers to ff(int);

7. When no function matches the pointers type exactly, the initialization results in a compile time error
8. The initialization of pf2 results in an error.

9. Double (*pf3) (int) = &ff; //comment


10. The above results in an error - no match of return type. 11. Matrix calc(const matrix &); Int calc(int, int); Int (*pc1)(int, int) = &calc; Int (*pc2)(int, double) = &calc;

12. No Type conversion between pointer to function types. Initialization of *pc2 results in error.

The Three steps of overload resolution:

1. Function Overload resolution is the process by which a function call is associated with one function in a set of overloaded functions.
2. The following is the example to explain the 3 steps. void f(); void main() void f(int); { void f(double, double = 3.4); f(5.6); void f(char*, char*); return 0; }

3. The 3 steps are:


a) Identify the set of overloaded functions considered for the call and identify the properties of the argument list in the function call.

b) Select the functions from the set of overloaded functions that can be called with the arguments specified in the call.
c) Select the function that best matches the call.

1. The set of functions of step 1 are called candidate functions.

2. A candidate function is a function with the same name as the function that is called..
3. All the 4 functions of the considered example.

4. The functions of step 2 are called viable functions.


5. A viable function has the same number of parameters as there are arguments and each additional parameter has an associated default argument and there must exist conversions that can convert each argument in the list to its corresponding parameter type. 6. In the example considered there are 2 viable functions that can be called: f(int), f(double, double) 7. If the 2nd step of function overload resolution finds no viable function, then the function call is in error. 8. The 3rd step is to select the best viable function.

9. For this, the conversions used to convert the arguments to the corresponding parameter types are ranked. 10. The best viable function is the function for which the conversions applied to the arguments are no worse than the conversions necessary to call any other viable function

11. When the viable function f(int) is considered, the conversion applied (double to int) is a standard conversion.
12. An exact match is better than a standard conversion. Bcoz Not to do a conversion is better than to do any conversion. 13. In the example considered the best viable function is f(double,double).

14. If the 3rd step of function overload resolution finds no best viable function, then the function call is ambiguous.

Argument Type Conversions


1. To select the best viable function, the conversions applied to convert the arguments to the corresponding parameter types are ranked. 2. The 3 possible outcomes of this ranking are a) An exact match The argument matches the type of parameter. void print(unsigned int); void print(const char*); void print(char); unsigned int a; print(a); print(a); print(a); b) Match with a type conversion void ff(char); ff(0); // int to char

c) No match Bcoz no type conversion exists void print(unsigned int); void print(const char*); void print(char); int *ip; print(ip); 1. For the argument to be an exact match, the argument need not exactly match the type of the parameter. 2. There are some minor conversions that can be applied to the argument 3. The possible conversions in exact match category are: a) Lvalue-to-rvalue conversion b) Array-to-pointer conversion c) Function-to-pointer conversion

d) Qualification conversions

Details of Exact Match:


1. The simplest case of an exact match is when the arguments match the type of the function parameters exactly. 2. Enum tokens{inline=128; virtual=129;}; tokens curtok = inline; enum stat{fail, pass}; void ff(tokens); void ff(stat); void ff(int); int main() { ff(pass); ff(0); //Matches which function? ff(curtok); } 3. Enumeration arguments matches exactly only the enumerators and the enum variables or enumerator types.

Lvalue-to-rvalue conversion

1. An lvalue is an object that a program can address from which a value can be fetched and its value can be modified unless the object is declared const.
2. An rvalue is an expression that denotes a value or is an expression that denotes a temporary object that the user cannot address and that cannot have its value modified. 3. Ex: int main() { int val, res; val = 5; res = calc(val); return 0; } 4. In the first expression val is the lvalue, and 5 is the rvalue. 5. In the second expression res is the lvalue and the temporary that holds the return value of the function call to calc() is the rvalue.

6. Int obj = obj1 + obj2; // comment

7. In some situations an expression that is an lvalue is used when a value is expected


8. Obj1 and obj2 are lvalue expressions.

9. Bfore addition is performed values are extracted from the 2 objects.


10. This action of extracting a value from an object represented by an lvalue expression is an lvalue-to-rvalue conversion.

11. When a function expects a pass by value argument, an lvalue-torvalue conversion is performed when the argument is an lvalue.
12. Ex: void print(int); int main() { int val=5; print(val); return 0; }

Array-to-pointer conversion 1. A function parameter never has an array type. True or false. 2. True, Instead the parameter is transformed to a pointer to the first element of the array. 3. This type of conversion is an array-to-pointer conversion. 4. Int a[3]; void putvalues(int *); int main() { putvalues(a); return 0; } 5. Even though putvalues has a pointer parameter and even though an array-to-pointer conversion takes place on the argument, the argument is an exact match for the call to putvalues.

Function-to-pointer conversion

1. As with a parameter of array type, a parameter of function type is automatically transformed to a pointer to the function.
2. This conversion is called function-to-pointer conversion.

3. Even though this conversion takes place, the argument is an exact match for a parameter of type pointer to function.
4. Typedef int (*pf1)(int &, int &);

int fun(int &, int &); void samp(int *, int *, pf1); void main() { int a[2], b[3]; samp(a, b, fun); }

Qualification conversions

1. A qualification conversion affects only pointers.


2. It is a conversion that adds const or volatile qualifiers (or both) to the type to which a pointer points.

3. Int *pi, *pj; bool fun(const int *, const int *); void main() { if (fun(pi, pj)) ..; }
4. The arguments pi and pj are converted from the type pointer to int to the type pointer to const int.

5. This conversion which adds a const qualification to the type to which the pointer points, is a qualification conversion.
6. The 3 conversions in exact match category (lvalue to rvalue, array to pointer, function to pointer) are referred to as lvalue transformations

1. An exact match with an lvalue transformation is ranked better than an exact match requiring a qualification conversion.

Match with a type conversion:


1. In this category several kinds of type conversions must be considered

2. The possible conversions can be grouped into three categories: Promotions, Standard conversions, and user defined conversions.
Details of a promotion

1. A promotion is one of the following conversions:


a) char, unsigned char, short ---to--- int. b) float ---to--- double c) enumeration type ---to--- int, unsigned int, long or unsigned long (first that can represent all the values of the enumeration constants) d) bool ---to--- int

Examples: 1. void manip(int); int main() { manip(a); return 0; }

2. Enum stat{fail, pass}; void ff(int); void ff(char); int main() { ff(pass); ff(0); return 0; } 3. In the first function call enumeration const is promoted to int.
4. Representation of an enumeration type depends on the values of the enumeration constants.

6. Enum e1{a1,b1,c1}; enum e2{a2, b2, c2=0x80000000}; void format(int); void format(unsigned int); int main() { format(a1); format(a2); return 0; } 7. The representation chosen for e1 is char. Bcoz a1,b1,c1 with values 0,1,2 can be represented by type char. 8. The representation chosen for e2 is unsigned int. bcoz one of the enumeration constants has a value of 0x80000000 which cannot be represented by char. 9. Format(a1); calls--- void format(int); 10. Format(a2); calls---- void format(unsigned int);

Details of Standard conversion

1. There are five kinds of conversions in the category of standard conversion:


a) Integral conversions: From any integral type or enumeration type to any other integral type b) Floating point conversions: From any floating point type to any other floating point type

c) Floating integral conversions: From floating point to integral or from integral to floating point types
d) Pointer conversions: Zero to pointer type, and conversion of pointer of any type to the type void* e) Bool conversions: From any integral type, floating point type, enumeration type, or pointer type to type bool.

Ex: void print(void*); void print(double); void main() { int i; print(i); print(&i); } 2. i is converted from int to double in first call and &i is converted from int* to void* in second call. 3. void print(int); void print(void*); void set(const char*); void set(char*);

void main() { print(0); set(0); } 4. 1st call matches print(int); 2nd call is ambiguous bcoz matches both

Pointers to Functions

Declaring a pointer to function


1. Int *pf(const string &, const string &); 2. In the above case the dereference operator is associated with the return type (the type specifier int) and not with pf. 3. Therefore the compiler interprets the statement as the declaration of a function named pf taking two arguments and returning a pointer. 4. Parentheses are necessary to associate the dereference operator (*) with pf ; int (*pf) (const string &, const string &); 5. An ellipse is also a part of function type. int printf(const char*, ); int strlen(const char*); int (*pf1) (const char*, ); int (*pf2) (const char*);

Initialization and assignment

1. Int compare(const string &s1, const string &s2) { return s1.compare(s2); }


int (*pf1) (const string &, const string &) = compare; int (*pf2) (const string &, const string &) = &compare; 2. Both initializations initialize the pointers to the function compare. 3. As array name evaluates to a pointer to its first element, the function name evaluates as a pointer to a function of its type. 4. A pointer to a function can also be assigned a value as follows: 5. Pf1 = compare; Pf2 = pf1; 6. Int Calc(int, int); int (*pf3) (int, int) = calc; pf3 = pf2;

7. The second assignment in the above example results in an error.

8. An initialization or assignment is legal only if the parameter list and return type of both the pointers (left-hand side and right-hand side) match exactly.
Invocation 1. Once a pointer to a function has been declared, it can be used to call the function to which it refers. 2. Int min(int*, int); int (*pf) (int*, int) = min; int a[5], size; void main() { min(a, size); // direct call pf(a, size); // in-direct call } 3. Both a direct call to the function using functions name and indirect call to the function using a pointer can be written same way.

4. The call pf(a, size); can also be written using the longhand explicit pointer notation. (*pf)(a, size); 5. . Int min(int*, int); int (*pf) (int*, int); const int size=5; int a[size]; void main() { min(a, size); pf(a, size); } 6. The second function call results in error bcoz pf has a value zero.

7. Only pointers that have been initialized or assigned to refer to a function can invoke a function.
Arrays of pointers to functions

1. It is possible to declare array of function pointers Ex:int (*arr[10]) ();


2. The above declares arr to be an array of ten elements. Each element is a pointer to a function that takes no arguments and that has a return type of int.

Generic Functions

1. A generic function defines a general set of operations that can be applied to various types of data.
2. For Ex: Quicksort algorithm is the same whether it is applied to an array of integers or array of floats. 3. By creating a generic function, one can define the nature of the algorithm independent of any data. 4. The compiler will automatically generate the correct code for the type of data that is used when executing the function. 5. In general creating a generic function means creating a function that can automatically overload itself.

6. A generic function is created using the keyword template.


7. The general form of template function definition is

1. Template <class Ttype> ret-type func-name(parameter list) { //function body } 2. Ttype is a placeholder name for a data type used by the function. The compiler will automatically replace it with actual datatype. 3. Template <class X> void swap(X &a, X &b) { X temp; temp = a; a = b; b = temp; } int main() { int I = 10; j = 20; double y = 10.1, z = 23.2; swap(i, j); swap(y, z); return 0; }

1. template <class X> void swap(X &a, X &b) tells the compiler two things: a) A template is being created b) X is the generic type. 2. In the above example the compiler creates two versions of swap(). One that will exchange integer values and the other that will exchange floating point values.

3. Important terms related to templates: i)A function definition preceded by a template statement is called a template function. ii)Generated function: A specific instance of a template function generated by the compiler. 4. The template clause of generic function does not have to be on the same line For Ex: template <class x> void swap(x &a, x &b) { ,.,.,.,.,..,.,}

5. Template <class x> Int I; // error No other stmt can occur betw template stmt & GFD Void swap(x &a, x &b) { ,..,..,..,.,,..} A Function with two Generic types 1. More than one Generic datatype can be defined in the template statement by using a comma separated list. For Ex: 2. Template <class type1, class type2> void func(type1 m, type2 n) { cout<<m<< <<n; } void main() { func(10, I like C++); func(98.6, 19L); } 3. In the example, the placeholders type1, type2 are replaced with datatypes int and char*, double and long respectively.

Explicitly overloading a generic function

1. Generic function overloads itself, but still can be explicitly overloaded. What is the difference?
2. Explicitly overloaded generic function overrides the generic function relative to that specific version. Template <class X> b = temp; void swap(X &a, X &b) cout<<Inside swap for int; { X temp; } temp = a; int main() a = b; { b = temp; int I = 10; j = 20; cout<<Inside template; double y = 10.1, z = 23.2; } swap(i, j); void swap(int &a, int &b) swap(y, z); { int temp; return 0; } temp = a; a = b;

1. The compiler does not generate the int version of generic swap function, bcoz the generic function is overridden by explicit overloading. 2. New-style syntax to denote explicit specialization template<> void swap<int> (int &a, int &b) { int temp; ---------; } 3. Template<> construct indicates specialization.

4. <int> indicates the type of data for which the specialization is being created.
Overloading a Function Template

1. To overload the template specification itself, simply create another version of the template that differs from others in its parameter list.
template <class x> void fun(x a) { cout<<This function accepts single parameter; }

template <class x, class y> void fun(x a, y b) { cout<< This function accepts two parameters; void main() { fun(10); fun(10, 20.5); }

2. Template for fun() is overloaded to accept either 1 or 2 parameters.


Using Standard parameters with Template Functions 1. Standard parameters can be mixed with generic type parameters in a template function. const int tabwidth = 8; Void main() template<class X> { tabout(100, 0); void tabout(X data, int tab) tabout(200, 1); { for(; tab; tab--) for(int I=0; I<tabwidth; I++) tabout(300, 2); cout<< ; } cout<<data<<\n; }

Generic Function Restrictions: 1. Generic functions are similar to overloaded functions except..? 2. With overloaded functions different actions may be performed within the body of each function, But a generic function must perform the same general action for all versions. Applying Generic Functions 1. Generic functions can be applied to situations whenever one has a function that defines a generalizable algorithm 2. Sorting is one operation for which generic functions were designed. 3. Another function that is benefited on being made into a template is, the function that compacts the elements in an array.

Generic Bubble Sort:

Template <class X> Void bubble(X *items, int n) { int I, j; X temp; for(I = 1; I<n; I++) for(j = n-1; j>=I; j--) if (items[j-1] > items[j]) { temp = items[j-1]; items[j-1] = items[j]; items[j] = temp; } } void main() { int ia[5] = {7, 5, 4, 8, 6}; double da[5] = {4.2, 3.1, 2.7, 6.8, 5.3}; bubble(ia, 5); bubble(da, 5); // DISPLAY }

Constructors and Destructors

1. C++ allows automatic initialization of objects when they are created. This is performed through the use of a constructor function.
2. Constructor is a special function that is a member of the class and has the same name as that class. 3. The Constructor is automatically called whenever an object of its associated class is created. 4. A Constructor is declared and defined as follows class stack Stack :: stack() { int stk[size]; { int top; top = 0; public: cout<<\n Stack Initialized; stack(); } void push(int I); Stack s1; //creates object s1 int pop(); }; //& initializes top to zero

5. For local objects, the constructor is called each time the object declaration is encountered. 6. For global or static local objects, constructor is called once. 7. If a normal member function is defined for initialization then that function should be invoked for each object separately, which is inconvenient if there are large number of objects. Special Characteristics 1. They should be declared in the public section. 2. Invoked automatically when the objects are created. 3. Do not have return types therefore cannot return values. 4. They cannot be inherited. 8.they make implicit calls to the operator

5. They can have default arguments. 6. Constructors cannot be virtual. 7. Cannot refer to their addresses.

NEW &DELETE when memor Allocation is necessary.

Destructors:

1. A destructor as the name implies is a complement of the constructor, used to destroy objects.

2. It will be invoked implicitly by the compiler upon exit from program o function or block 3. Local objects are destroyed when the block is left. Global objects are destroyed when the program terminates. 4. It is a member function whose name is same as the class name but is preceded by a tilde (~) operator. Ex : ~stack();

5. There are many reasons why a destructor may be needed. Ex: An object may need to deallocate memory that it had previously allocated, or close a file that it had opened. 6. A destructor never takes any argument nor does it return any value

7. It is a good practice to declare destructors in a program since it releases memory space for future use.

Illustration of Destructors:

Int count = 0; Class sample { public: sample() { count++; cout<<Object <<count; cout<< Created \n; } ~sample() { cout<<Object <<count; cout<< Destroyed \n; count--; } };

Void main() { sample s1, s2, s3; { sample s4; } { sample s5; } } Output Object 1 created Object 2 created Object 3 created Object 4 created Object 4 destroyed Object 4 created Object 4 destroyed Object 3 destroyed Object 2 destroyed Object 1 destroyed

Structures and Classes

1. Class is syntactically similar to a struct. The only difference between them is that by default all members are public in a struct and private in a class. void main() Struct emp class emp { { void getdata(); { int empno; s1.getdata(); void putdata(); char name[10]; s1.putdata(); private: public: } int empno; void getdata(); char name[10]; void putdata(); }s1; };
Why C++ contains two virtually equivalent keywords

1. C structures already provide a means of grouping data therefore it is just a small step to allow them to include member functions
2. It may be easier to port existing C programs to C++ bcoz structures and classes are related.

Unions and Classes

1. C++ unions may contain both member functions and variables. Union members are public by default.
2. A union in C++ retains its C feature that all data elements share the same location in memory. Void swapbyte :: swap() union swapbyte { unsigned char t; { void swap(); t = c[0]; void setbyte(unsigned short i); c[0] = c[1]; void show(); c[1] = t; private: } unsigned short u; Void main() unsigned char c[2] { swapbyte b; }; b.setbyte(49034); Void swapbyte :: show() b.swap(); { cout<<u; } b.show(); Void swapbyte :: setbyte(unsigned short i) } { u = i; }

3. A union may also include constructors and destructors.

4. It is best to use a class when we want a class, and a struct when we want a C-like structure.
Restrictions on C++ unions

A union cannot inherit any other classes of any type.


A union cannot be a base class. A union cannot have virtual member functions.

No static variables can be members of union.


A reference member cannot be used. A union cannot have as a member any object that overloads the = operator. No object can be a member of a union if the object has an explicit constructor or destructor function.

Anonymous Unions

1. An anonymous union does not include a type name, and no objects of the can be declared.
2. So the variables are referred to directly without the dot operator syntax. Void main() l = 100000; { d = 123.2342; union cout<<l<< ; { cout<<d<< ; long l; } double d; }; 3. Anonymous union tells the compiler that its member variables are to share the same location. 4. The names of the members of an anonymous union must not conflict with other identifiers known within the same scope.

5. All restrictions on unions apply to anonymous unions in addition to the following: a) No member functions are allowed, only data. b) Cannot contain private or protected elements.

c) Global anonymous unions must be specified as static.


Friend Functions 1. Private members cannot be accessed from outside the class i.e by a non-member function 2. C++ allows a non-member function to access private members of a class by using a friend function.

3. A friend function need not be a member of any class.


4. To make an outside function friendly to a class, include its prototype within the class, preceding it with the keyword friend.

5. The function is defined elsewhere in the program like a normal C++ function (without using the keyword friend or the scope operator ::). class avg Float mean(avg s) { return float(s.a +s.b) / 2.0; } { int a , b; public: Void main() void setvalue() { avg a1; a1.setvalue(); { a = 25; b=40; } cout<< Average is : <<mean(a1); friend float mean(avg s); } }; Characteristics of Friend Functions 1. A Friend function is not in the scope of the class to which it has been declared as friend.

2. Therefore it cannot be called using the object of the class and must be invoked like a normal function.
3. It cannot access the member names directly and has to use an object name and dot operator with each member name.

2. It can be declared either in private or public part of a class.

3. Usually it has objects as arguments.


Use of Friend Functions 1. Are useful in overloading certain types of operators.

2. Friend functions are used in situations where two classes like to share a particular function Ex: Two classes manager and scientist sharing a function income_tax().
3. FFs make the creation of some types of I/O functions easier. Member function of one class can be friend function of another class. 1. In such cases they are defined using the scope resolution operator.

Class x { . int fun1(); . }

Class y { . friend int x :: fun1(); .. }

All member functions of one class as friend functions of another class

1. In such cases, the class is called a friend class


Class x { . int fun1(); . } Class z { . friend class x; . }

Function friendly to two classes Class abc; //Forward declaration Class xyz; { int x; public: void setvalue() { x = 10; } friend void max(xyz, abc); }; Class abc { int a; public: void setvalue() { a = 20; } friend void max(xyz, abc); };

Void max(xyz m, abc n) { if(m.x >= n.a) cout<<m.x; else cout<<n.a; } Note:

Void main() { abc obj1; obj1.setvalue(); xyz obj2; obj2.setvalue(); max(obj2, obj1); }

1. Function max() has arguments from both xyz and abc. 2. When the function max() is declared as a friend in xyz for the first time, the compiler will not acknowledge the presence of abc unless its name is declared in the beginning called forward declaration.

Defining Inline functions within a Class

1. When a function is defined inside a class declaration, it is automatically made into an inline function.
2. Therefore all restrictions that apply to inline functions also apply to functions defined inside the class declaration. 3. It is not necessary to precede its declaration with the inline keyword. 4. Constructor and destructor functions may also be inlined, either by default or explicitly. class sample { int a , b; public: void setvalue() { a = 25; b=40; } void show(); } Void sample :: show() { cout<<a = <<a<< <<b = <<b; }

Parameterized constructors

1. In practice it may be necessary to initialize the various data elements of different objects with different values when they are created.
2. This can be achieved by passing arguments to the constructor function when the objects are created. 3. Such Constructors that take arguments are called parameterized constructors. Sample :: sample(int x, int y) Class sample { int m, n; public: sample(int x, int y); void display(void) { cout<<\n m = <<m; cout<<\n n = <<n; } }; { m = x; n = y; } Void main() { sample s1(0,100); sample s2 = sample(25, 75); cout<<\n OBJECT 1 ; s1.display(); cout<<\n OBJECT 2 ; s2.display(); }

4. When a constructor has been parameterized, The object declaration statement such as sample s1 may not work. 5. Initial values are to be passed as arguments to the constructor function when the object is declared. This can be done in two ways: a) By calling the constructor explicitly b) By calling the constructor implicitly 6. Explicit Call: sample s1 = sample(0, 100);

7. Implicit Call: sample s1(0, 100);


A special case of constructors with one parameter 1. If a constructor has only one parameter, there is a third way to pass an initial value to that constructor sample s1 = 100; // s1 is declared and initialized 2. The above declaration statement is handled by the compiler as Sample s1 = sample(100);

Static Class Members

1. Both data members and member functions of a class can be made static.
Static Data Members(SDM) 1. Preceding a data members declaration with the keyword static tells the compiler that only one copy of that variable will exist and that all objects of the class will share that variable. 2. A static data member is initialized to zero when the first object of its class is created. No other initialization is permitted. 3. Declaring a static data member is not defining it (means not allocating storage for it). Remember class is a logical construct that does not have physical reality. 4. Defining a static data member is done outside the class by redeclaring the static variable using the scope resolution operator . 5. SDM are normally used to maintain values common to entire class

Class item { static int count; int num; public: void getdata(int val) { num = val; count++; } void getcnt() { cout<<count : <<count; } };

Int item :: count; //defining

Main() { item i1, i2; i1.getcnt(); i2.getcnt(); i1.getdata(100); i2.getdata(200); i1.getcnt(); i2.getcnt(); }

1. Bcoz there is only one copy of count shared by all the objects. The two output statements cause the value 2 to be displayed
2. While defining a static data member, some initial value can also be assigned to the variable Ex: int item :: count = 10;

Use of static data members:

1. One use of a static member variable is to provide access control to some shared resource used by all objects of a class.
2. For Ex: U might create several objects, each of which needs to write to a specific disk file, However only one object can write to the file at a time. In this case declare a static variable that indicates when the file is in use and when it is free. Each object then interrogates this variable before writing to the file.

3. Another use of SMV is to keep track of the number of objects of a particular class type that are in existence.
4. A public static data member can be accessed by outside function using the class name as follows class name :: data member

Class counter { public: static int count; counter() { count++; } ~counter() { count--; } }; int counter :: count; void fun() { counter temp; cout<<\nObjects in use: ; cout<<counter :: count; }

Void main() { counter o1; cout<<\nObjects in use: ; cout<<counter :: count; counter o2; cout<<\nObjects in use: ; cout<<counter :: count;

f();
cout<<\nObjects in use: ; cout<<counter :: count;

Static Member Functions(SMF)

There are several restrictions placed on Static member functions.


1. A static function can have access to only other static members declared in the same class.

2. Global functions and data may be accessed by SMF.


3. A SMF does not have a this pointer. 4. There cannot be a static version and non-static version of the same function 5. A SMF may not be virtual. 6. They cannot be declared as const or volatile

7. A static member function can be called using the class name as follows Class-name :: function-name;
8. Use is to preinitialize private static data before any object is created

Class static_type

Int static_type :: n;

{ static int n; Public: static void init(int x) { n = x; } void show() { cout<<n; } }; Scope Resolution Operator

Void main()
{ //static data bfore object creation static_type :: init(100);

static_type x; x.show();
}

1. In C++ several different classes can use the same function name, the compiler knows which function belongs to which class bcoz of scope resolution operator The :: operator links a class name with a member name in order to tell the compiler what class the member belongs to. Ex: void stack :: push(int i);

2. Allows access to global version of a variable. Int m = 10; Void main() { int m = 20; { int k = m; int m = 30; cout<<k = <<k<<\n; cout<<m = <<m<<\n; cout<<::m = <<::m<<\n; } cout<<m = <<m<<\n; cout<<::m = <<::m<<\n; }

Nested Classes

1. Defining one class within another creates a nested class. This is one way of Inheriting properties of one class into another.
2. That is a class can contain objects of other classes as its members.

class alpha{..};
class beta{..}; class gamma { alpha a; beta b;

};
3. Nested classes are rarely used because of C++s powerful inheritance mechanism.

Local Classes

1. A Class defined within a function is called a Local Class.


Void fun() { class sample { int x; public: void putx(int n){x = n; } int getx() { return x; } }ob; ob.putx(10); cout<<ob.getx(); } Void main() { fun(); }

2. When a class is declared within a function, it is known only to that function and unknown outside of it.

Restrictions on local classes

1. All member functions must be defined within the class declaration.


2. Local class may not use or access local variables of the function in which it is declared Except..

3. A local class has access to static local variables declared within the function or those declared as extern.
4. No static variables may be declared inside a local class.

5. Local class may access type names and enumerators defined by the enclosing function.
Passing Objects to Functions 1. Objects can be passed to functions just the same way as any other type of variable. 2. Although the passing of objects is straightforward some Unexpected events occur that relate to constructors and destructors.

Class myclass { int x; public: myclass(int n); ~myclass(); void set_x(int n) { x = n; } int get_x() { return x; } }; Myclass::myclass(int n) { x = n; cout<<Constructing <<x; }

myclass :: ~myclass()

{ cout<<Destroying <<x; }
Void fun(myclass ob) { ob.set_x(2); cout<< Local x: <<ob.get_x(); } Void main() { myclass o(1); fun(o); cout<< x in main: ; cout<<o.get_x(); }

1. According to the output, there is one call to constructor and two calls to the destructor. Why?

1. When an object is passed to a function, a copy of that object is made(and this copy becomes the parameter) 2. This means that a new object comes into existence. 3. When the function terminates, the copy of the argument is destroyed.

4. Is the objects constructor called when the copy is made?


5. Is the objects destructor called when the copy is destroyed? 6. When a copy of an argument is made during a function call, the normal constructor is not called. Instead the objects copy constructor is called. 7. We can explicitly define a copy constructor for a class.

8. However if a class does not explicitly define a copy constructor, then C++ provides one by default.
9. The default copy constructor creates a bitwise(i.e identical) copy of the object

Copy Constructor

1. A copy constructor is used to declare and initialize an object from another object sample(sample & s)
For Ex: sample s2(s1) Declares the object s2 and at the same time initialize it to the values of s1 2. Another form: sample s2 = s1; 3. The statement s1 = s2; will not invoke the copy constructor.

Class code { int id; public: code(){ } code(int a) { id = a; } code(code & x) { id = x.id; } void display() { cout<<id; } };

Void main() { code a(100); code b(a); code c = a; code d; d = a; Cout<<a.display()<<b.display(); Cout<<c.display()<<d.display(); }

Returning Objects Void main() { myclass o; o = fun(); cout<<o.get_x(); }

Class myclass { int x; public: void set_x(int n) { x = n; } int get_x() { return x; } }; myclass fun() { myclass m; m.set_x(2); return m; }

1. When an object is returned by a function, a temporary object is automatically created that holds the return value.
2. It is this object that is actually returned by the function. After the value has been returned, this object is destroyed

3. The destruction of this temporary object may cause unexpected side effects. 4. For Ex: if the object returned by the function has a destructor that frees dynamically allocated memory , that memory will be freed even though the object that is receiving the return value is still using it. 5. Ways to overcome this problem:

. Overloading the assignment operator

Defining a copy constructror

Object Assignment 1. An object can be assigned to another provided they are of same type.

2. This causes the data of the right side object to be copied into left side object

Class myclass { int x; public: void set_x(int n) { x = n; } int get_x() { return x; } };

Void main() { myclass obj1, obj2; obj1.set_x(99); ob2 = ob1; cout<< X value of obj 2: ; cout<<obj2.get_x(); }

3. By default, all data from one object is assigned to the other by use of a bit-by-bit copy. 4. It is possible to overload the assignment operator and define some other assignment procedure.

Creating Initialized and uninitialized arrays of objects

If a class defines a parameterized constructor, an array declared of this class type must be initialized. Void main() Class c1 { c1 ob[3]; //error { int I; c1 ob[3] = {1, 2, 3}; //initializers public: for(int I=0; I<3; I++) c1(int j){ I = j; } cout<<ob[I].get_I(); int get_I(){ return I;} } };
There are two initialization syntaxes Shorthand form: c1 ob[3] = {1, 2, 3};

Longhand form: c1 ob[3] = {c1(1), c1(2), c1(3)};


Note: If an objects constructor requires two or more arguments, longhand form will have to be used

Class c1 { int h, I; public: c1(int j, int k){ h = j; I = k; } int get_I(){ return I;} int get_h(){ return h;} };

Void main() { c1 ob[2] = {c1(1, 2), c1(3, 4)}; for(int I = 0; I<2; I++) { cout<<ob[I].get_h()<< ; cout<<ob[I].get_I(); } }

Uninitialized arrays can be called by including a constructor that takes no parameters. Class c1 { int I; public: c1() { I = 0; } // called for non-initialized arrays c1(int j){ I = j; } // called for initialized arrays int get_I(){ return I;} };

Pointers to Objects 1. When accessing members of a class, given a pointer to an object, an arrow operator is used instead of dot operator. Class c1 Void main() { int I; { c1 ob(88), *p; public: p = &ob; c1(int j){ I = j; } cout<< p->get_I(); int get_I(){ return I; } } };

2. When a pointer is incremented, it points to the next element of its type. Class c1 { int I; public: c1() {I = 0; } c1(int j){ I = j; } int get_I(){ return I;} }; Void main() { c1 ob[3] = {1, 2, 3}; c1 *p; p = ob; //start addr assigned for(int I = 0; I<3; I++) { cout<<p.get_I()<<\n; p++; } }

3. The address of a public member of an object can be assigned to a pointer and then that member can be accessed by using the pointer. Void main() Class c1 { c1 ob(1); { public: int *p; int I; p = &ob.I; c1(int j){ I = j; } cout<< *p; }; } Type Checking C++ Pointers

1. One pointer can be assigned to another only if two pointer types are compatible.
2. For Ex: int *pi, *pj; float *pf; pi = pj // No type mismatch pi = pf // error, type mismatch

This Pointer

1. When a member function is called, it is automatically passed an implicit argument that is a pointer to the invoking object. This pointer is called this Pwr :: pwr(double base, int exp) Class pwr { b = base; e = exp; val = 1; { double b; if(e == 0) return; int e; For( ; e>0; e--) double val; val = val *b; public: } pwr(double base, int exp); Void main() double get_pwr() { pwr x(4.0 , 2), y(2.5 , 1); { return val; } cout<<x.get_pwr()<< ; }; cout<<y.get_pwr()<< ; }
2. Within a member function, the members of a class can be accessed directly, For Ex: b = base;

3. The same statement can also be written as this -> b = base;

4. This pointer points to the object that invoked pwr().


5. Using standard form is easier than using this pointer. 6. However this pointer is very important when operators are overloaded 7. Friend functions are not members of a class and therefore are not passed a this pointer.

8. Static member functions do not have a this pointer.


Pointers to Class Members 1. C++ allows to generate a special type of pointer that points to a member of a class not to a specific instance of that member in an object. 2. This sort of pointer is called a pointer to class-member or pointer to member. (Not the same as normal C++ pointers)

3. Since member pointers are not true pointers, the . and -> cannot be applied to them. 4. Special pointer-to-member operators .* and ->* are used to access a member of a class given a pointer to it.

Class c1 { public: c1(int i) { val = I;} int val; int double_val() { return val + val; } }; Void main() { int c1::*data; int (c1::*func)( );

c1 ob1(1), ob2(2);
data = &c1:: val; //get offset of val func = &c1:: double_val; //get offset.

cout<<ob1.*data;<< <<ob2.*data;
cout<<\n Doubled values:; cout<<(ob1.*func) ( )<< ; cout<<(ob2.*func) ( ); } // end of main

Points to Note

1. When declaring pointers to members, you must specify the class and use the scope resolution operator. (data and func of Example).
2. Must use .* operator when accessing a member of an object by using an object and ->* operator if a pointer to an object is used in accessing a member Class c1 c1 ob1(1), ob2(2); c1 *p1, *p2; { public: p1 = &ob1; p2 = &ob2; c1(int i) { val = I;} data = &c1:: val; //get offset of val int val; func = &c1:: double_val; //get offset. int double_val() cout<<p1->*data;<< <<p2->*data; { return val + val;} cout<<\n Doubled values:; }; cout<<(p1 ->*func) ( )<< ; Void main() cout<<(p2 ->*func) ( ); { int c1::*data; } // end of main int (c1::*func)( );

Pointers to members are different from pointers to specific instances of elements of an object int c1::*d; p = &o.val; // addr of specific val int *p; c1 o; d = &c1::val //offset of generic val Operator Overloading 1. The mechanism of giving additional meaning to an operator is known as operator overloading. Operator Overloading Restrictions 1. The following operators cannot be overloaded a) Class member access operators(. , .*) b) Scope resolution operator(::) c) Size operator(sizeof) d) conditional operator(?:) 2. The precedence of an operator cannot be altered.

3. Cannot change the number of operands that an operator takes.

4. Except for the function call operator( ( ) ), operator functions cannot have default arguments.

5. When an operator is overloaded its original meaning should not be lost. Ex: The operator + which has been overloaded to add two vectors can still be used to add two integers. 6. Except for the = operator , operator functions are inherited by a derived class Creating a member operator function 1. Operators are overloaded by creating operator functions, which defines an additional task to an operator. 2. The general form of an operator function is returntype classname :: operator #(arg-list) { function body // task defined }

3.

# is the placeholder representing the operator being overloaded, operator # is the function name.

4. Operator function must be either member function (non-static) or friend function. a) A friend function will have only 1 argument for unary operators and 2 for binary operators b) A member function has no arguments for unary operators and only 1 for binary operators.

Overloading Binary Operators


1. The functional notation of adding two numbers c = sum(a, b);

2. The arithmetic notation by overloading + operator c = a + b;


3. The left-hand operand is used to invoke the operator function and the right-hand operand is passed as an argument.

Class complex

Complex complex :: operator +(complex op2)

{ float x, y; public: complex() { } complex(float real, float img) { x = real; y = img; } complex operator +(complex); void show() { cout<< x << + ; cout<< y << j ; } };

{ complex temp; temp.x = x + c.x; temp.y = y + c.y; return temp; } Void main()
{ complex c1, c2, c3; c1 = complex(2.5, 3.5); c2 = complex(1.5, 2.5); c3 = c1 + c2;

cout<<\n c1 = ; c1.show(); cout<<\n c2 = ; c2.show(); cout<<\n c3 = ; c3.show(); }

Note: operator +() is a member function and receives only one complex type argument. 1. The function is expected to add two complex values and return a complex value but receives only one value as argument. Where does the other value come from? 2. C3 = C1 + C2 // invokes operator +() function Here C1 takes the responsibility of invoking the function C2 plays the role of an argument that is passed to the function 3. The above invocation is equivalent to C3 = C1.operator+(C2) 4. The data members of c1 are accessed directly and the data members of c2 are accessed using the dot operator. 5. Temp object creation can be avoided by replacing the entire function body by the following statement: return complex((x + c.x), (y + c.y))

6. On encountering such a statement the Compiler invokes an appropriate constructor, initializes an object with no name and returns the contents for copying into an object. 7. Such an object is called a temporary object and goes out of space as soon as the contents are assigned to another object.

8. Using temporary object, makes code shorter, more efficient and better to read.
9. Instead of statement c3.show(); It is possible to have a stmt like (c1 + c2) .show(); 10. In the above case c1 + c2 generates a temporary object that ceases to exist after the call to show() terminates.

Overloading Unary Operators


1. The operator function takes no arguments. 2. The only one operand is implicitly passed by using the this pointer.

Class sample Sample sample :: operator ++() { int val1, val2; { val1++; val2++; return *this; } public: Void main() sample() { } { sample s1(10, 20), s2(5, 30); sample(int a, int b) s1.show(); // displays 10 20 { val1 = a; s2.show(); // displays 5 30 val2 = b; } ++s1; void show() s1.show(); //displays 11 21 { cout<<val1<< ; s2 = ++s1; cout<<val2; } s1.show(); //displays 12 22 sample operator ++(); s2.show(); // displays 12 22 }; } Overloading the Shorthand Operators 1. Shorthand Operators such as +=, -= can also be overloaded. 2. They are binary operators and the operator function takes one arg. (Its Basically combining assignment with another type of operation)

Class sample { int val1, val2; public: sample() { } sample(int a, int b) { val1 = a; val2 = b; } void show() { cout<<val1<< ; cout<<val2; } sample operator+=(sample); };

Sample sample :: operator +=(sample s) { val1 = s. val1 + val1; val2 = s.val2 + val2; return *this; } Void main() { sample s1(10, 20), s2(5, 30); s1.show(); // displays 10 20 s2.show(); // displays 5 30 s1+=s2; s1.show(); //displays 15 50 }

Creating Prefix and Postfix Forms of the Increment and Decrement Operators
1. C++ allows creating prefix and postfix versions of the increment or decrement operators.

2. To do this, we must define two versions of the operator++() function

3. The general forms for the prefix and postfix ++ and -- operator functions. Pre-Increment Post-Increment
type operator++() type operator++(int x)

{ } { } 4. If the ++ follows its operand, the operator++(int x) is called and x has the value zero. 5. If the ++ precedes its operand, the operator++() is called.
6. Older versions of C++ does not support specifying separate prefix and postfix versions of ++ or --, the prefix form was used for both.

** In C++ if the = is not overloaded, a default assignment operation is created automatically for any class.
The default assignment is simply a member-by-member, bitwise copy

Overloading Special Operators

1. C++ allows overloading special operators like array subscripting ( [ ] ), function call operator (( )), ClassMember access operator ( ->).
2. The restrictions on overloading these operators are they must be non static member functions, and they cannot be friends. Overloading [ ] (It is considered as binary operator) 1. The general form of member operator[ ] () function is type class-name :: operator[ ](int i) 2. Technically, the parameter does not have to be of type int, but an operator[] ( ) function is typically used to provide array subscripting and as such, an integer value is generally used. 3. The expression O[3]; results in a call to operator[] ( ) function 4. O[3] is equivalent to O. operator[] (3 ).

Class atype { int a[3]; Void main() public: { atype(int i, int j, int k) atype ob(1, 2, 3); { a[0] = i; a[1] = j; a[2] = k; } cout << ob[1]; int operator [ ](int i) } { return a[i]; } }; [ ] can be used on both left and right sides of an assignment statement. To do so simply specify the return value of operator[]() as a reference. Class atype { int a[3]; public: atype(int i, int j, int k) { a[0] = i; a[1] = j; a[2] = k; } int &operator [ ](int i) { return a[i]; } }; Void main() { atype ob(1, 2, 3); cout << ob[1]; cout<< ; ob[1] = 25; cout<< ob[1]; }

1. In C++ It is possible to overrun or underrun an array boundary at runtime without generating a run-time error message. 2. The advantage of overloading the [ ] operator is that it allows a means of implementing safe array indexing in C++. 3. Create a class that contains the array and allow access to that array only through the overloaded [ ] operator then out-of-range index can be intercepted. Int& atype :: operator [ ](int i) Class atype { { int a[3]; if(i<0 || i>2) public: { cout<< Boundary Error\n; atype(int i, int j, int k) exit(1); { a[0] = i; a[1] = j; a[2] = k; } } int &operator [ ](int i); return a[i]; }; }

Void main() { atype ob(1, 2, 3); cout << ob[1]; // Displays 2 cout<< ; ob[1] = 25; // calls the operator funtion cout<< ob[1]; ob[3] = 44; // Generates run-time error, 3 out-of-range } 4. In the above program when the statement ob[3] = 44; executes, the boundary error is intercepted by operator [ ] ( ) and the program is terminated before any damage can be done.

Overloading ( ), -> operators is left as an assignment


comma operator: Comma operator is a binary operator. 1. The comma operator strings together several expressions.

2. The left side of comma operator is always evaluated as void.

3. The expression on the right side becomes the value of the total comma-separated expression.
4. Ex: x = (y = 3, y + 1); first assigns y the value 3 and then assigns x the value 4. 5. The parantheses are necessary bcoz the comma operator has a lower preedence than the assignment operator. 6. When comma operator is used on the right side of assignment statement, the value assigned is the value of the last expression of the comma-separated list. sample(int a, int b) Overloading comma operator { val1 = a; Class sample val2 = b; } { int val1, val2; void show(); public: sample operator +(sample op2); sample() { } Sample operator ,(sample op2); };

Void sample :: show()

{ cout<<val1<< ; cout<<val2; } Void main() { sample s1(10, 20); sample s2(5, 30); Sample sample :: operator , (sample op2) sample s3(1, 1); { Temp.val1= op2.val1 ; s1.show(); s2.chow(); Temp.val2= op2.val2; s3.show(); cout<<\n; cout<<op2.val1<< << op2.val2; s1 = (s1, s2+s2, s3); return temp; } s1.show(); } Overloading << and >> (Input and Output operators)
1. The << and >> operators are overloaded in C++ to perform I/O operations on C++s built-in-types.

Sample sample :: operator + (sample op2) { sample temp; Temp.val1= op2.val1 + val1; Temp.val2= op2.val2 + val2; return temp; }

2. They can be overloaded to perform I/O operations on user-types

INHERITANCE

1. The mechanism of deriving a new class from an old one is called Inheritance.
2. The concept of Inheritance provides the idea of reusability. This is basically done by creating new classes, reusing the properties of the existing ones. 3. A class that is inherited is referred to as base class, and a class that inherits is called the derived class.

4. Different types of Inheritance:


A A B A

B Single Inheritance

C Multiple Inheritance

Hierarchical Inheritance

C Multilevel Inheritance

D Hybrid Inheritance

1. A derived class with only one base class is called single Inheritance.
2. Deriving a class from multiple base classes is called Multiple Inheritance.

3. The process of inheriting the properties of a class by more than one class is Hierarchical Inheritance
4. The mechanism of deriving a class from another derived class is Multilevel Inheritance.

1. The general form of defining a derived class

class derived-class-name : visibility-mode base-class-name


{Members of Derived class}; 2. The colon indicates that the derived-class-name is derived from the base-class-name. 3. The visibility mode is optional, and is private by default. 4. Ex: class ABC : private XYZ

{ members of ABC }; //Private derivation


class ABC : public XYZ { members of ABC class ABC : XYZ { members of ABC }; //private derivation by default }; // public derivation

Derived Class Publicly Inherited

Class base { int i, j; public: void set(int a, int b) { i = a; j = b; } void show() { cout<<i<< <<j; } };
Void main() { derived ob(3);

Class derived : public base { int k; public: derived(int x) { k = x; } void showk() { cout<<k<<\n; } };

ob.set(1 , 2); // accesses member of base ob.show(); // accesses member of base ob.showk(); // uses member of derived }

Derived Class Privately Inherited

Class base { int i, j; public: void set(int a, int b) { i = a; j = b; } void show() { cout<<i<< <<j; } };
Void main() { derived ob(3);

Class derived : private base { int k; public: derived(int x) { k = x; } void showk() { cout<<k<<\n; } };

ob.set(1 , 2); // error, cannot access set() ob.show(); // error, cant access show() ob.showk(); // access member of derived }

Protected Members 1. When a member of a class is declared as protected, that member is not accessible by other nonmember elements of the program. 2. In other words access to a protected member is the same as access to a private member.

3. A protected member differs from private only w.r.t Inheritance.


a) A private member of a base class is not inherited by the derived class.

b) Protected members are inherited by the derived class.


c) By using protected, one can create class members that are private to their class but can still be inherited and accessed by a derived class

d) If the base class is inherited in public mode then all protected members of base class become protected in derived class
e) If the base class is inherited in private mode then all protected members of base class become private in derived class.

Class base { protected: int i, j; public: void set(int a, int b) { i = a; j = b; } void show() { cout<<i<< <<j; } }; Void main() { derived ob;

Class derived : public base { int k; public: void setk() // D can access i, j { k = i* j; } void showk() { cout<<k<<\n; } };

ob.set(2 , 3); // OK known to derived ob.show(); // OK known to derived ob.setk(); ob.showk(); }

Class base { protected: int i, j; public: void set(int a, int b) { i = a; j = b; } void show() { cout<<i<< <<j; } }; Class derived2 : public derived1 { int m; public: void setm() { m = i - j; } void showm() { cout<<m<<\n; } };

Class derived1 : public base { int k; public: void setk() // can access i, j { k = i* j; } void showk() { cout<<k<<\n; } }; Void main() { derived1 ob1; derived2 ob2; ob1.set(2 , 3); ob2.set(3 , 4); ob1.show(); ob2.show(); ob1.setk(); ob2.setk(); ob.showk(); ob2.showk(); ob2.setm(); ob2.showm(); }

1. When a derived class is used as a base class for another derived class, any protected member of the initial base class that is inherited by the first derived class may also be inherited as protected again by a second derived class.(Base inherited by derived as public) 2. In the above example derived2 has access to i and j. 3. If base were inherited as private, then all members of base would become private members of derived 1, which means that they would not be accessible by derived2. 4. Example program for the above statement is left as an exercise. 5. The program in the previous slide can be quoted as an example for Multilevel Inheritance. 6. The most important point to note is: Private members of base class are not inherited by the derived class what ever be the access specifier or the mode of inheritance.

5. When the access specifier is public , all public members of the base class become public members of derived class, all protected members of base class become protected members of derived class. 6. When the access specifier is private , all public and protected members of the base class become private members of the derived class 7. When the access specifier is protected , all public and protected members of the base class become protected members of the derived class.

Base class Derived class Access Specifier visibility public private protected Private Not inherited Not inherited Not inherited Protected Protected Private Protected

Public

Public

Private

Protected

Protected Base-Class Inheritance

1. When a base class is inherited as protected, all public and protected members of base class become protected members of derived class. Class base void setk() { protected: { setk(10, 12); k = i*j; } int i, j; void showall() public: { cout<<k<< ; showij(); } void setij(int a, int b) }; { I =a; j = b; } Void main() void showij() { derived ob; { cout<<i<< <<j<< \n; ob.setij(2, 3); // illegal }; ob.setk(); //ok ob.showall(); //ok Class derived : protected base ob.showij(); //illegal { int k; } public:

Inheriting Multiple Base Classes (Multiple Inheritance)

1. As discussed earlier, a derived class inheriting two or more base classes is called multiple inheritance Class base1 Class base2 { protected: { protected: int x; int y; public: public: void showx() void showy() { cout<< x <<\n ; } { cout<< y <<\n ; } }; };
Class d1: public base1, public base2 { public:

Void main()
{ derived ob; ob.set(10, 20); ob.showx(); ob.showy(); }

void set(int m, int n)


{ x = m; y = n; } };

Constructors, Destructors and Inheritance

1. It is possible for a base class, a derived class, or both to contain constructors and destructors.
2. Two things to be discussed relative to constructors and destructors when Inheritance is involved a) When base-classs and derived-classs constructors and destructors are called (order of execution) b) How parameters are passed to base class constructors. Execution of constructors and destructors w.r.t Inheritance When a derived class object is created, the base class constructor will be called first, followed by derived class constructor.

When a derived object is destroyed, its destructor is called first followed by the base class destructor
Put differently constructors are executed in their order of derivation and destructors are executed in reverse order of derivation.

Class base Output { Constructing base public: base() { cout<< constructing base\n ; } Constructing derived ~base() { cout<< Destructing base \n; } Destructing derived }; Destructing base Class derived : public base { public: derived() { cout<< Constructing Derived\n ; } ~derived() { cout<< Destructing derived \n; } }; Void main() { derived ob; }

In case of multilevel inheritance, the general rule of execution applies

Class base { public: base() { cout<< constructing base \n; } ~base() { cout<< Destructing base \n ; } }; Class derived1 : public base { public: derived1() { cout<< Constructing Derived1\n ; } ~derived1() { cout<< Destructing derived1 \n; } }; Class derived2 : public derived1 { public: derived2() { cout<< Constructing Derived2\n ; } ~derived2() { cout<< Destructing derived2 \n; } };

Void main() { derived2 ob; } Output Constructing base Constructing derived1 Constructing derived2

Destructing derived2
Destructing derived1 Destructing base In case of multiple Inheritance constructors are called in the order of derivation, left to right, as specified in deriveds Inheritance list and destructors in reverse order.

Class base1 { public: base1() { cout<< constructing base1\n ; } ~base1() { cout<< Destructing base1 \n; } }; Class base2 { public: base2() { cout<< constructing base2\n ; } ~base2() { cout<< Destructing base2 \n; } }; Class derived : public base1, public base2 { public: derived() { cout<< Constructing Derived\n ; } ~derived() { cout<< Destructing derived \n; } };

Void main() { derived ob; } Output Constructing base1 Constructing base2 Constructing derived Destructing derived Destructing base2 Destructing base1

If the deriveds Inheritance list is as follows

Class derived : public base2, public base1


The the output will be

Output
Constructing base2 Constructing base1

Constructing derived
Destructing derived Destructing base1

Destructing base2

Passing parameters to base class constructors

1. The arguments to a base-class constructor are passed via arguments to the derived class constructor by using the Expanded derived-class constructor declaration.
2. The General form of it is: derived-constructor(arg-list) : base1(arg-list), .baseN(arg-list) { // Body of derived constructor } 3. Here base1 through baseN are the names of the base classes inherited by the derived class Class base { protected: int I; public: base(int x) { I = x; cout<<constructing base; ~base() { cout<<\n Destructing base; };

Class derived : public base { int j; public: derived(int x, int y) : base(y) { j = x; cout<<constructing derived\n; } ~derived() { cout<< Destructing derived \n; } void show() { cout<<i<< <<j<<\n; } }; Void main() { derived ob(3, 4) ob.show(); // displays 4 3 } The derived class constructor must declare both, the parameters that it requires as well as any required by the base class

Note: Even if a derived class constructor does not use any arguments, it will still need to declare one if the base class requires it. In this situation, the arguments passed to the derived class are simply passed along to the base. Class base1 Class base2 { protected: int i; { protected: int k; public: public: base1(int x) base2(int x) { i = x; cout<<constructing base1; {k=x; cout<<constructing b2; ~base1() ~base2() { cout<<\n Destructing base1; { cout<<\n Destructing b2; }; }; Class derived : public base1, public base2 { public: derived(int x, int y) : base1(x), base2(y) { cout<< Constructing Derived\n ; } ~derived() { cout<< Destructing Derived\n ; }

Void show() { cout<<I<< <<k<<\n;} }; // End of Derived class Void main() { derived ob(3, 4); ob.show(); } Granting Access 1. When a base class is inherited a private, All public and protected members of that class become private members of derived class. 2. Suppose that u want to restore one or more inherited members to their original access. 3. For Ex: U might want to grant certain public members of base class public status in the derived class even though the base class is inherited as Private 4. In C++ there are two ways to accomplish this a) By using a Using statement that supports namespaces b) Second, to employ an access declaration within the derived class

5. General form of Access Declaration base-class :: member ; 6. The access declaration is put under appropriate access heading in the derived class declaration. Note: No type declaration is allowed in access declaration Class derived : private base Class base { public: { int I; base :: j; // make j public again public: base :: seti; intr j, k; base :: I; // illegal cant elevate access void seti(int x) { I = x; } int a; void geti() { return I; } }; }; Void main() ob.seti(10); //legal { derived ob; ob.j = 20; //legal ob.k = 10; // illegal }

Virtual Base Classes

1. There is an ambiguity when multiple base classes are inherited Void main() Class base { d3 ob; { public: int I; }; ob.I = 10; // Which I ????? Class d1 : public base ob.j = 20; { public: int j; }; ob.k = 30; ob.sum = ob.I + ob.j + ob.k; Class d2 : public base cout<<ob.I<< ; { public: int k; }; cout<<ob.j<< <<ob.k<< ; Class d3 : public d1, public d2 cout<<ob.sum; { public: int sum; }; }
Note: There are two copies of base present in an object of type derived3 There are two ways to overcome this problem: 1) To use scope resolution operator and manually select one i

2) To Use Virtual base classes.


Void main() { derived3 ob; }; ob.d1 :: I = 10; // d1s i Class d1 : public base ob.j = 20; { public: int j; }; ob.k = 30; Class d2 : public base ob.sum = ob.d1 :: I + ob.j + ob.k; { public: int k; }; cout<<ob.d1 :: I<< ; cout<<ob.j<< <<ob.k<< ; Class d3 : public d1, public d2 cout<<ob.sum; { public: int sum; }; } 1. The second option of using virtual base classes prevents multiple copies of base class from being present in derived class Class base { public: int I; 2. This is done by preceding the base class name with the keyword virtual when it is inherited.

Class base { public: int I;

};

Class d1 : virtual public base { public: int j; }; Class d2 : virtual public base { public: int k; }; Class d3 : public d1, public d2 { public: int sum; };

Void main() { d3 ob; ob.I = 10; // unambiguous ob.j = 20; ob.k = 30; ob.sum = ob.I + ob.j + ob.k; cout<<ob.I<< ; cout<<ob.j<< <<ob.k<< ; cout<<ob.sum; }

1. D1 and D2 inherited base as virtual, any multiple inheritance involving them will cause only one copy of base to be present
2. D1 ob1; ob1.I = 88; //valid

Virtual Functions and Polymorphism Polymorphism

Compile- time Polymorphism

Runtime Polymorphism

Function Overloading

Operator Overloading

Virtual Functions

CTP: Linking the function call to the appropriate function is done at compile time. Also called Early Binding or Static Binding or Static Linking RTP: Linking the function call to the appropriate function is done at Runtime. Also called Late Binding or Dynamic Binding

1. By using pointers to objects and Virtual Functions run-time polymorphism can be achieved 2. A pointer declared as a pointer to base class can also be made to point to derived class object. This is perfectly valid. 3. For Ex: D d; B *ptr; ptr = &b; B b; ptr = &d;

4. There is a problem with ptr in accessing public members of derived class D. Only those members inherited from B and not the members that originally belong to d can be accessed. Class B { public: int b; Class D : public B { public: int d; void show() { cout<<b=<<b<<\n; cout<<d=<<d<<\n; } };

void show()
{ cout<<b=<<b<<\n; } };

Void main()

{ B *bptr; B base;
bptr = &base; bptr->show(); D derived; bptr = &derived; bptr->show(); bptr->b = 200; bptr->b = 100; cout<< bptr points to base object\n;

Each time bptr->show() is encountered, it executes base class show() function.

cout<< bptr points to derived object\n; D *dptr; dptr = &derived; dptr->d = 300; cout<<dptr is derived type pointer\n; dptr->show(); }

1. A Virtual function is a member function that is declared within a base class and redefined by a derived class. 2. To create a virtual function, precede the functions declaration in the base class with the keyword Virtual.

Class base
{ public: virtual void vfunc()

Class d2: public base


{ public: void vfunc()

{ cout<< This is bases Vfunc;}


}; Class d1 : public base };

{ cout<<This is d2s Vfunc;}


Void main()

{ public:
void vfunc() { cout<< This is d1s Vfunc;} };

{ base *p, b;
d1 do1; d2 do2; p = &b; //continued

p->vfunc(); // access bases vfunc

p = &do1;
p->vfunc(); // access d1s vfunc p = &do2;

Output This is bases vfunc This is d1s vfunc This is d2s vfunc

p->vfunc(); // access d2s vfunc


} 1. Inside base vfunc() is declared as virtual . 2. When d1 and d2 redefines vfunc, the keyword virtual is not needed. But not an error if u include. 3. The prototype for a redefined virtual function must match exactly the prototype specified in the base class. 4. If prototype is changed when redefining a virtual function, the function will be considered overloaded by C++ compiler, and its virtual nature will be lost.

Restrictions on Virtual Functions 1. Virtual Functions must be non-static members of the classes. 2. They cannot be Friends. 3. Constructor functions cannot be virtual, but destructor functions can

4. A Virtual function can be friend of another class.


5. The prototype of base class version of a virtual function and all derived class versions must be identical.

6. Base pointer can point to derived object but reverse is not true.
7. When a base pointer points to derived class, incrementing or decrementing it will not make it to point to the next object of Dclass.

8. If a virtual function is defined in the base class. It need not necessarily be redefined in the derived class.
9. A Virtual function in base class must be defined, even though it may not be used.

Calling a Virtual Function Through a Base Class Reference

1. A reference is an implicit pointer. Thus a base class reference can be used to refer to an object of the base class or any object derived from that base.
2. The common situation in which a virtual function is invoked through a base class reference is when the reference is a function parameter. Class base Class d2: public base { public: { public: virtual void vfunc() void vfunc() { cout<< This is bases Vfunc;} { cout<<This is d2s Vfunc;} }; }; Class d1 : public base Void f(base &r) { public: { r.vfunc(); } void vfunc() Void main() { cout<< This is d1s Vfunc;} { base b; }; d1 do1; d2 do2; //contd

f(b); // pass a base object to f()

f(d1); // pass a d1 object to f()


f(d2); // pass a d2 object to f() }//end of main

The Virtual Attribute is Inherited


1. When a virtual function is inherited, its virtual nature is also inherited, means no matter how many times a virtual function is inherited , it remains virtual Class d1 : public base Class base { public: { public: void vfunc() virtual void vfunc() { cout<< This is d1s Vfunc; { cout<< This is bases Vfunc; } } }; };

Class d2 : public d1 { public: void vfunc()//vfunc is still virtual { cout<< This is d2s Vfunc;} }; Void main() { base *p, b; d1 do1; d2 do2;

p = &b;

p->vfunc(); // access bases vfunc


p = &do1; p->vfunc(); // access d1s vfunc

p = &do2;
p->vfunc(); // access d2s vfunc }

Output This is bases vfunc This is d1s vfunc This is d2s vfunc

Virtual Functions are Hierarchcial

1. As said earlier a virtual function does not have to be overridden. When a derived class fails to override, then when an object of that derived class accesses that function, the function defined by the base class is used. Class base { public: virtual void vfunc() { cout<< This is bases Vfunc; } };
Class d1 : public base { public: void vfunc() { cout<< This is d1s Vfunc; } };

Class d2 : public base { public: // vfunc not overriden }; Void main() { base *p, b; d1 do1; d2 do2; Output This is bases vfunc p = &b; This is d1s vfunc p->vfunc(); // access bases vfunc This is bases vfunc p = &do1; p->vfunc(); // access d1s vfunc p = &do2; p->vfunc(); // access bases vfunc } Because Inheritance is Hierarchical in C++. It makes sense that virtual functions are also hierarchical.

When a derived class fails to override a virtual function, the first redefinition found in reverse order of derivation is used. Void main() Class base { base *p, b; { public: virtual void vfunc() d1 do1; d2 do2; { cout<< This is bases vfunc; } p = &b; }; p->vfunc(); // access base vfunc p = &do1; Class d1 : public base p->vfunc(); // access d1s vfunc { public: p = &do2; void vfunc() p->vfunc(); // access d1s vfunc { cout<< This is d1s Vfunc; } }; } Output Class d2 : public d1 This is bases vfunc { public: This is d1s vfunc // vfunc not overriden by d2 This is d1s vfunc

Pure Virtual Functions

1. A Pure Virtual Function is a Virtual function that has no definition within the base class.
2. The General form of declaring a Pure Virtual Function:

virtual type func-name(param-list) = 0;


3. When a Virtual Function is made pure, any derived class must provide its own definition. If the derived class fails to override the Pure Virtual Function, a compile time error will result. Class number { protected: int val; public: void setval(int I) { val = I; } virtual void show() = 0; //pure }; }; Class hextype : public number { public:

void show()
{ cout<<hex<<val<<\n; }

Class dectype : public number { public: void show() { cout<<val<<\n; } }; Void main() { dectype d; hextype h; octtype o; d.setval(20); d.show(); //displays 20 h.setval(20); h.show(); // displays 14 o.setval(20); o.show(); // displays 24 }

Class octtype : public number { public: void show() { cout<<oct <<val<<\n; } }; The Ex: illustrates how a base class may not be able to mraningfully define a virtual function When a Virtual Function is declared as Pure, all derived classes must override it. If a derived class fails to do this, a compile-time error will result

Abstract Classes

1. A class that contains atleast one pure virtual function is said to be abstract
2. An abstract class constitutes an incomplete type that is used as a foundation for derived classes. 3. Cannot create objects of an abstract class, can create pointers and references to an abstract class. 4. Class number in previous program is an example of an abstract class

Early vs. Late Binding

Early Binding
Occurs when all information needed to call a function is known at compile time. Means object and function call are bound during compilation. Ex: Normal function calls, Function Overloading, Operator Overloading. The main advantage is efficiency (Faster Execution)

Late Binding
Refers to function calls that are not resolved until run time

Means object and function are not linked until runtime.


Ex: Virtual functions

The main adv is flexibility means LB allows creation of programs that can respond to events occurring while the program executes there by reducing code.
Slower Execution times

I/O Operations

1. C++ uses the concept of stream and stream classes to implement the I/O Operations. A stream acts as an interface between the program and I/O device.
C++ Streams

1. A stream is a sequence of bytes. It acts either as a source from which the input data can be obtained or as a destination to which output data can be sent. 2. The source stream that provides data to the program is called the input stream.
3. The destination stream that receives output from the program is called output stream. 4. The data in the input stream can come from keyboard or any other storage device. 5. The data in the output stream can go to the screen or any other storage device.

Input Device

Input stream

Extraction from input stream

Program
Output Device Output stream Insertion into output stream

1. C++ contains several predefined streams that are automatically opened when a program begins its execution. 2. These include cin and cout. Cin represents the standard input stream. Cout represents the standard output stream.

ios

istream

streambuf

ostream

iostream

Istream_withassign

Iostream_withassign

Ostream_withassign

Stream Classes for console I/O Operations

1. ios is the base class for istream and ostream which are inturn base classes for iostream. 2. The class ios is declared as Virtual base class so that only one copy of its members are inherited by the iostream

ios

Contains basic facilities that are used by other I/O classes Contains a pointer to a buffer object Inherits the properties of ios Declares input functions such as get(), getline() and read() Contains Overloaded Extraction operator>> Inherits the properties of ios Declares output functions such as put() and write() Contains overloaded insertion operator<< Inherits the properties of istream and ostream and thus contains all input output functions

istream

ostream

iostream

streambuf Provides an interface to physical devices through buffers

put() and get() Functions

1. There are two types of get() functions get(char *) and get(void).


void main() { char c; cin.get(c); while(c!=\n) { cout.put( c); cin.get(c); }

reads and displays a line of text including white spaces


>> operator can also be used to read a character but will skip white spaces and newline character the get(void) version is used as follows c = cin.get(); // the value returned by the function is assigned to variable c.

2. The function put() , a member of ostream class can be used to output a line of text, character by character. 3. For Ex. cout.put(x); // displays character x cout.put(ch); //displays the value of variable ch cout.put(68); // displays the character d

getline() and write() Functions

1. Reads and displays line of text . The general form is: cin . getline(line, size);
2. char name[20]; cin.getline(name, 20); 3. getline() function can read strings that contain white spaces also 4. After reading the string cin automatically adds the terminating null character. 5. cout.write(line , size); Ex: cout.write(name, size); 6. If the size is greater than the length of line, then write() function displays beyond the bounds of line. 7. It is possible to concatenate two strings using the write() function cout.write(string1, m). write(string2, n);

Formatted console I/O Operations

1. C++ supports a number of features that could be used for formatting the output. These features include
a) ios class functions and flags b) Manipulators c) User-Defined output functions Function Task ios format functions

Width()
Precision() Fill() Setf()

Unsetf()

To specify the required field size for displaying an output value To specify the number of digits to be displayed after the decimal point of a float value To specify a character that is used to fill the unused portion of a field To specify format flags that control the form of output To clear the flags specified

2. Manipulators are special functions that can be included in the I/O statements to format the parameters of a stream 3. To access these manipulators , the file iomanip.h should be included in the program

4. In addition to the manipulators supported by C++, User defined manipulators can be created
Manipulators Setw() Equivalent ios General Form function Width() Cout.width(w) // w is no. of columns

Setprecision()
Setfill() Setiosflags() Resetiosflags()

Precision()
Fill() Setf() Unsetf()

Cout.precision(d)// d is the no. of digits to the right of decimal point Cout.fill(ch) // ch is the character Cout.setf(arg1, arg2) Cout.unsetf(arg1, arg2)

Width() (default is the size of the value)

Cout.width(5);
Cout<<543<<12;

5 4 3 1 2

Width function will specify the field width for only one item. After printing one item it will revert back to default If the specified field width is smaller than the size of the value to be printed, C++ expands the field to fit the value.

Precision() (default is six digits after decimal point)


Cout.precision(2); Cout.width(5);

1 .

6 7

Cout<<1.6666;
The output is rounded to nearest cent Trailing zeros are truncated

Precision setting stays in effect until it is reset

Fill()

Cout.fill(*);
Cout.width(10); Cout<<3977;

* * * * * * 3 9 7 7

Like precision(), fill() stays in effect till we change it


Banks and Financial Institutions use this kind of padding while printing cheques etc. Setf() Cout.setf(arg1, arg2) arg1 is one of the formatting flags defined in the class ios

arg2 ( bit field) specifies the group to which the formatting flag belongs
Cout.setf(ios::left, ios::adjustfield); Cout.width(7)

H E L L O

Cout<<HELLO;

Format Required Left-justified output Right-justified output

Flag (arg1) ios :: left ios :: right

Bit-field (arg2)

ios :: adjustfield

Padding after sign or base indicator Scientific notation


Fixed Point notation Decimal base Octal base Hexadecimal base

ios :: internal
ios :: scientific ios :: fixed ios :: dec ios :: oct ios :: hex ios :: floatfield

ios :: basefield

Note: First argument should be one of the group members of the second argument

Cout.fill(*);

Cout.precision(3);

- * * * * * 1 . 2 4 3 e + 0 1

Cout.setf(ios :: internal, ios :: adjustfield); Cout.setf(ios :: scientific, ios :; floatfield); Cout.width(15); Cout<<-12.431276; Displaying Trailing zeroes and + sign

Certain flags that do not bit-fields are used as single arguments in setf() to achieve this.
ios :: showpoint - Displays trailing zeroes ios :: showpos - Print + before Positive numbers Cout.setf(ios :: showpoint); Cout.setf(ios :: showpos); Cout<<13.230000;

+ 1 3 .

2 3 0 0 0 0

Manipulators

1. These provide the same features as that of ios member functions.


2. Some manipulators are more convenient to use than their equivalent ios member functions bcoz two or more manipulators can be used as a chain in one statement 3. For Ex: cout<< manip1<<manip2<<manip3; useful in displaying several columns of output Manipulator Setw(int w) Meaning Sets the field width to w Example Cout<<setw(10);

Setprecision(int d)

Sets the floating point precision to d Setfill(int c) Sets the fill character to c Setiosflags(long f) Sets the format flag f Resetiosflags(long f) Clears the flag specified endl Insert new line

Cout<<setprecision(2);
Cout<<setfill(*);

Cout<<setiosflags(ios :: left)
Cout<<endl

User Defined Manipulators 1. The general form for user defined manipulators 2. Ostream & manipulator(ostream & output) { . return output; } 3. Ostream & unit(ostream & output) { output<< inches; return output; } 4. The statement cout<<36<<unit; //displays 36 inches

Potrebbero piacerti anche