Download as pdf or txt
Download as pdf or txt
You are on page 1of 73

INTRODUCTION TO C++

Basic Concepts of Object-Oriented Programming


It is necessary to understand some of the concepts used extensively in object-oriented programming. They include: Objects Classes Data abstraction and encapsulation inheritance Polymorphism Dynamic binding Message passing

We shall discuss these concepts in some detail in this section.

Objects Objects are the basic run-time entities in an object-oriented system. They may represent a person. a place. a bank account, a table of data or any item that the program has to handle. They may also represent user-defined data such as vectors, time and lists. Programming problem is analyzed in terms of objects and the nature of communication between them, Program objects should be chosen such that they match closely with the real world objects.

Objects take up space in the memory and have an associated address like a record in Pascal, or a structure in C. When a program is executed, the objects interact by sending messages to one another, For example, if customerand account are two objects in a program, then the customer object may send a message to the account object requesting for the bank balance. Each object contains data, and code to manipulate the data. Objects can interact without having to know the details of each others data or code. It is sufficient to know the type of message accepted, and the type of response returned by the objects.. Fig. below shows two notations that are popularly used in object

Classes A class is thus a collection of objects of similar type. The class of an object defines what attributes an object has.

For example. : triangle, square, circle are objects of the class shapes. Attributes of shapes are length, breadth and height. Member functions could be area(), perimeter() etc. The entire set of data and code of an object can be made a user-defined data type with the help of a class. In fact, objects are variables of the type class. Once a class has been defined, we can create any number of objects belonging to that class. Each object is associated with the data of type class with which they are created.

Classes are user-defined data types and behave like the built-in types of a programming language. if Shapes has been defined as a class, then the statement : Shapes square ; will create an object square belonging to the class shapes.

Data Abstraction and Encapsulation The wrapping up of data and functions into a single unit (called class) is known as Encapsulation. Data encapsulation is the most striking feature of a class. The data is not accessible to the outside world, and only those functions which are wrapped in the class can access it. These functions provide the interface between the objects data and the program. Abstraction refers to the art of representing essential features without including the background details or explanations. Classes use the concept of abstraction and are defined as a list of abstract attributes such as size, weight and cost. and functions to operate on these attributes. They encapsulate all the essential properties of the objects that are to be created. The attributes

are sometimes called data members because they hold information. The functions that operate on these data are sometimes called methods or member functions. Since the classes use the concept of data abstraction, they are known as Abstract Data Type. (ADT).

Inheritance Inheritance is the process by which objects of one dass acquire the properties of objects of another class. It supports the concept of hierarchical classification. For example, triangleis a part of the dass shapes . The principle behind this sort of division is that each derived class shares common characteristics with the class from which it is derived as illustrated in Fig below.

SHAPES
len Perimeter() Area()

TRIANGLE
Len, breadth, ht. Area(), peri()

SQUARE
Side Area(), peri()

In OOP , the concept of inheritance provides the idea of reusability. This means that we can add additional features to an existing class without modifying it. This is possible by deriving a new class from the existing one.

The new class will have the combined features of both the classes. The advantage of the inheritance mechanism is that it allows the programmer to reuse a class that is almost. but not exactly, what he wants, Note that each sub class defines only those features that are unique to it. without the use of classification, each class would have to explicitly include all of its features.

Polymorphim Polymorphism is another important OOP concept. Polymorphism, a Greek term. means the ability to take more than one form. An operation may exhibit different behaviours in different instances. The behaviour depends upon the types of data used in the operation. For example, consider the operation of addition. For two numbers, the operation will generate a sum. If the operands are strings, then the operation would produce a third string by concatenation. The process of making an operator to exhibit different behaviours in different instances is known as operator overloading. Figure below illustrates that a single function name can be used to handle different number and different types of arguments. This is something similar to a particular word having several different meanings depending on the context. Using a single function name to perform different types of tasks is known as function overloading. Polymorphism plays an important role in allowing objects having different internal structures to share the same external interface. This means that a general class of operations may be accessed in the same manner even though specific actions associated with each operation may differ Polymorphism is extensively used in implementing inheritance.

Dynamic Binding Binding refers to the linking of a procedure call to the code to be executed in response to the call. Dynamic binding (also known as late binding) means that the code associated with a given procedure call is not known until the time of the call at run-time. It is associated with polymorphism and inheritance. A function call associated with a polymorphic reference depends on the dynamic type of that reference. Consider the procedure draw in Fig. above. By inheritance, every object will have this procedure. Its algorithm is, however, unique to each object and so the draw procedure will be redefined in each class that defines the object. At run-time, the code matching the object under current reference will be called.

Message Passing

An object-oriented program consists of a set of objects that communicate with each other. The process of programming in an object-oriented language, therefore. involves the following basic steps: 1 Creating classes , that define objects and their behaviour, 2. Creating objects from class definitions, and 3. Establishing communication among objects. Objects communicate with one another by sending and receiving information much the same way as people pass messages to one another, The concept of message passing makes it easier to talk about building systems that directly model or simulate their real-world counterparts

A message for an object is a request for execution of a procedure, and therefore will invoke a function (procedure) in the receiving object that generates the desired result. Message passing involves specifying the name of the object, the name of the function (usage) and the information to be sent. Example:

Objects have a life cycle. They can be created and destroyed. Communication with an object is feasible as long as it is alive.

Structure of C++ Program A typical C++ program would contain four sections as shown in Fig below These sections may be placed in separate code files and then compiled independently or jointly.

It is a common practice to organize a program into three separate files, The class declarations are placed in a header file and the definitions of member functions go into another file. This approach enables the programmer to separate the abstract specification of the interface (class definition) from the implementation details (member functions definition). Finally, the main program that uses the class is placed in a third file which includes the previous two files as well .

Basic data types in C++ are:

Derived Data Types Arrays The application of arrays in C++ is similar to that in C. The only exception is the way character arrays are initialized. When initializing a character array in ANSI C. the compiler will allow us to declare the array size as the exact length of the string constant For instance. char string[3] = xyz; is valid in ANSI C. It assumes that the programmer intends to leave out the null character \0 in the definition.

But in C++. the size should be one Larger than the number of characters in the string. char string[4] = xyz; // O.K. for C++

Symbolic Constants There are two ways of creating symbolic constants in C++: Using the qualifier const, and Defining a set of integer constants using enum keyword. in both C and C++ , any value declared as const cannot be modified by the program in any way. However, there are some differences in implementation. In C++, we can use const in a constant expression, such as const int size =10; char name[size];

The named constants are just like variables except that their values cannot be changed.

Another method of naming integer constants is by enumeration as

enum { X, Y, Z}; this defines X, Y, Z as integers constants with values 0, 1, and 2 repective1y. This is equivalent to: const X = 0; const Y = 1; const Z = 2; We can also assign values to X, Y, and Z explicitly. Ex:

Enum{X =100, Y=50, Z =200); Such values can be any integer values.

Type Compatibility C++ defines int , short int , and long int as three different types. They must be cast when their values are assigned to one another. Similarly, unsigned char, char, and signed char are considered as different types, although each of these has a size of one byte. In C++ the types of values must be the same for complete compatibility, or else, a cast must be applied.

A Simple C++ Program Let us begin with a simple example of a C++ program that prints a string on the screen.

Eg: /* average*/

#include<iostream.h> #include<conio.h>

void main()

float num1, num2 , sum, avg; clrscr(); cout << "enter 2 numbers : "; cin >> num1; // reads numbers

cin >> num2; // from keyboard

sum = num1+ num2; avg = sum/2;

cout << " sum = " << sum << "\n"; cout << "average = "<< avg << "\n";

getch();

Program Features

The iostream File

We have used the following include directive in the program

#include <iostream.h> This directive causes the preprocessor to add the contents of the iostream file to the program. It contains declarations for the identifier cout and the operator <<

C++ program is a collection of functions. The above example contains only one function, main() As usual, execution begins at main(). Every C++ program must have a main(). C++. statements terminate with semicolons.

Comments

C++ introduces a new comment symbol // (double slash). For multiple lines: same as in C

/* more than one line Multiple lines */

Output Operator :

The only statement in Program is an output statement. The statement cout << C++ is better than C. causes the string in quotation marks to be displayed on the screen. This statement introduces two new C++ features. cout and <<. The identifier cout pronounced as C out) is a predefined object that represents the standard output stream in C++. Here, the standard output stream represents the screen. The operator << is called the insertion or put to operator. It inserts (or sends the contents of the variable on its right to the object on its left (Fig below)

The object cout contains a simple interface. If string represents a string variable, then the following statement will display it contents:

cout string; You may recall that the operator << is the bit-wise left-shift operator and it can still be used for this purpose. This concept is known as operator overloading, an important aspect of polymorphism.

Input operator:

The statement: cin >> num1; Is an input statement and waits for the user to type a number from the keyboard. The identifier cin pronounced as C in) is a predefined object that represents the standard input stream in C++. Here, the standard input stream represents the keyboard.

The operator >> is called the extraction or get from operator. It extracts (or takes the value from the keyboard and assignsit to the variable on its right to the object on its left (Fig below)

Namespace

This defines a scope for the identifiers that are used in a program. For using the identifiers defined in the namespace scope we must include the using directive, like using namespace std; // using and namespace are the new keywords of C++.

Here. std is the namespace where C++ standard class libraries are defined. All ANSI C++ programs must include this directive. This will bring all the identifiers defined in std to the current global scope .

Reference Variables

A reference variable provides an alternative name for a previously defined variable. For example, if we make the variable sum a reference to the variable total. then sum and total can be used interchangeably to represent that variable, A reference variable is created as follows: data-type reference-name = variable-name

Example: float total = 100; float &sum = total; // now sum and total are same.

total is a float type variable that has already been declared. sum is the alternative name declared to represent the variable total. Both the variables refer to the same data object in the memory, Now, the statements cout << total;

and

cout << sum;

both print the value 100. The statement : total = total + 10;

will change the value of both total and sum to 110. Likewise, the assignment sum=0; will change the value of both the variables to zero.

A reference is like a const pointer to a variable. Assigning a reference is like using a pointer with ( &) and not with ( * ). Here we assign a variable to a reference variable.

A major application of reference variables is in passing arguments to functions. Consider the following: (Call by reference)

void f(int & x) // uses reference { x = x+10: // x is incremented; so also m

} void main ( ) { int m = 10; f(m); // function call . } When the function call f(m) is executed, the following initialization occurs: int & x = m;

Thus x becomes an alias of m after executing the statement f(m); Such functions calls are known as calls by reference. Since the variable x and m are aliases, when the function increments x, m is also incremented. The value of m becomes 20 after the function is executed.

Operators in C++

All C operators are valid in C++ also. in addition, C++ introduces some new operators. We have already seen two such operators. namely, the insertion operator << , and the extraction operator >>. Other new operators are; Scope resolution operator -Pointer-to-member declarator-Pointer-to-member operator-Pointer-to-member operator-Memory release operator-Line feed operator-Memory allocation operator-Field width operator-:: : :* -->* .* delete endl new setw

In addition, C++ also allows us to provide new definitions to some of the built-in operators. That is, we can give several meanings to an operator, depending upon the types of arguments used. This process is known as operator overloading.

Scope resolution operator: In C, the global version of a variable cannot be accessed from within the inner block. C++ resolves this problem by introducing a new operator :: called the scope resolution operator. This can be used to uncover a hidden variable. It takes the following form:

This operator allows access to the global version of a variable. For example. ::count. means the global version of the variable count (and not the local variable count declared in that block).

/* scope resolution operator*/

#include<iostream.h> #include<conio.h>

int m = 10;

// m is global

void main()

int m = 20; { int k = m; int m = 30; clrscr();

// m is local to main

// m is local to inner block

cout << " we are in inner block\n";

cout << "k= "<<k<<"\n"; cout << "m= "<<m<<"\n"; cout << "::m= "<< ::m <<"\n"; }

cout << "\n we are in outer block \n"; cout << "m= "<<m<<"\n"; cout << " ::m= "<< ::m <<"\n"; getch(); }

Memory management operators:


C++ defines two unary operators new and delete that perform allocating and freeing of memory.

An object can be created by using new, and destroyed by using delete, as and when required. A data object created inside a block with new, will remain in existence until it is explicitly destroyed by using delete. . The new operator can be used to create objects of any type. It takes the following general form: Data-type variable = new data-type ;

eg:

int p = new int ; float q = new float ;

Subsequently, the statements

p = 25;

and q = 7.5;

assigns 25 to the newly created int object and 7.5 to the float object. We can also initialize the memory using the new operator. This is done as follows:

Here value specifies the initial value. Examples: int *p = new int(25); float *q = new float(7.5);

the general form for a one dimensional array is :

Eg: int *p = new int[10]; creates memory space for 10 integers.

Note: if sufficient memory is not available, malloc and new return NULL Ponter.

When a data object is no longer needed, it is destroyed to release memory space for reuse. The general form is:

The pointer variable is a pointer that points to the object created with new. Eg: delete p; delete q;

Manipulators
Manipulators are operators that are used to format the data display. The most commonly used manipulators are endl and setw. The endl manipulator, when used in an output statement, causes a line feed to be inserted. It has the same effect as using the newline character \n. For example, the statement: cout << m = << m << endl ; cout << n = << n << endl ; cout << p = << p << endl ; would cause three lines of output, one for each variable. If we assume the values of the variables as 2597, 14. and 175 respectively, the output will appear as follows:

setw: right justified.

Use: <iomanip.h>

Eg: cout << setw(5) << sum << endl; The manipulator setw(5) specifies a field width 5 for printing the value of the variable sum. This value is right-justified within the field as shown below:

Type Cast Operator

C++ permits explicit type conversion of variables or expressions using the type cast operators The following two versions are equivalent; (type-name) expression // C notation

type-name (expression) Examples:

// C++ notation

average = sum / (float)i; average = sum / float(t);

// C notation // C++ notation

Functions

Structure of a function is similar to C.

Inline functions

One of the objectives of using functions in a program is to save some memory space, which is useful when a function is likely to be called many times. However, every time a function is called, it takes a lot of extra time in executing a series of instructions for tasks such as jumping to the function, saving registers, pushing arguments into the stack, and returning to the calling function. When a function is small, a substantial percentage of execution time may be spent in such overheads.

To eliminate the cost of calls to small functions, C++ provides a new feature called inline function. An inline function is a function that is expanded in line when it is invoked. That is, the compiler replaces the

function call with the corresponding function code (something similar to macros expansion). The inline functions are defined as follows:

Example: inline double cube(double a) { return(a * a * a); } The above inline function can be invoked by statements like c = cube(3.0) ; d = cube(2.5 + 1.5) ; On the execution of these statements, the values of c and d will be 27 and 64 respectively.

inline expansion makes a program run faster because the overhead of a function call and return is eliminated. Advantage : execution is faster

Disadvantage : size of the executable file increases with number of function calls

Eg: /* inline functions*/

#include<iostream.h> #include<conio.h> #include<iomanip.h>

inline float mul(float x, float y) { return(x*y); }

inline double div(double p, double q) { return(p/q); }

void main() {

float a = 12.34; float b = 9.82; clrscr(); cout << mul(a, b) << endl; cout << div(a, b) << endl; getch();

Default Arguments C++ allows us to call a function without specifying all its arguments. In such cases. the function assigns a default value to the parameter which does not have a matching argument in the function call. Default values are specified when the function is declared, The compiler looks at the prototype to see how many arguments a function uses and alerts the program for possible default values. Here is an example of a prototype (i.e. function declaration) with default values:

float amount (f1oat principle , int period , float rate = 0.15) ; The above prototype declares a default value of 0.15 to the argument rate. A subsequent function call like value = amount(5000 , 7) ; // one argument missing

passes the value of 5000 to principal and 7 to period and then lets the function use default value of 0.15 for rate. The call value = amount(5000 , 5 , 0.12) ; passes an explicit value of 0.12 to rate. // no missing argument

Function overloading
As stated earlier, overloading refers to the use of the same thing for different purposes. C++ also permits overloading of functions. This means that we can use the same function name to create functions that perform a variety of different tasks. This is known as function polymorphism in OOP.

For example, an overloaded add() function handles different types and number of data as shown below: // Declarations int add(int a, int b); int add(int a, int b, int c); double add(double x, double y); double add(int p, double q); double add(double p , int q); // prototype 1 // prototype 2 // prototype 3 // prototype 4 // prototype 5

// Function calls cout << add(5 10); cout << add(15, 10.0); cout << add(12.5, 7.5); cout << add(5, 10. 15); cout << add(0.75, 5); // uses prototype 1 // uses prototype 4 // uses prototype 3 // uses prototype 2 // uses prototype 5

eg : /* function overloading*/ /* function volume() is overloaded 3 times.*/

#include<iostream.h> #include<conio.h>

int volume(int); double volume(double, int); long volume(long, int, int);

void main()

{ clrscr(); cout << volume(10) << endl; cout << volume(2.5, 8) << endl; cout << volume(100L, 75, 15) << endl; getch(); }

//function definitions

int volume(int s) { return(s*s*s); } //cube

double volume(double r, int h) {

return(3.14 *r *r *h); }

//cylinder

long volume(long l, int b, int h) {

return(l*b*h); }

//cuboid

Rules: A function call first matches the prototype having the same number and type of arguments and then calls the appropriate function for execution. A best match must be unique. The function selection involves the following steps: 1. The compiler first tries to find an exact match in which the types of actual arguments are the same, and use that function. 2. If an exact match is not found, the compiler uses the integral promotions to the actual arguments, such as, char to int float to double to find a match.

3. When either of them fails. the compiler tries to use the built-in conversions (the implicit assignment conversions) to the actual arguments and then uses the function whose match is unique. If the conversion is possible to have multiple matches. then the compiler will generate an error message. Suppose we use the following two functions: long square (long n) double square(double x) A function call such as square(10); will cause an error because int argument can be converted to either long or double thereby creating an ambiguous situation as to which version of square() should be used.

4. If all of the steps fail, then the compiler will try the user-defined conversions in combination with integral promotions and built-in

conversions to find a unique match. user-defined conversions are often used in handling class objects.

Classes

Classes in C++ are similar to structures in C. The only difference is that members of a structure are by default public. (i.e accessible to entire program) whereas the members of a class by default are private.

Specifying a C1ass A class is a way to bind the data and its associated functions together. It allows the data (and functions) to be hidden. if necessary, from external use. When defining a class we are creating a new abstract data type that can be treated like any other built-in data type. generally, a class specification has two parts: 1. Class declaration 2. Class function definitions The class declaration describes the type and scope of its members. The class function definitions describe how the c1ass functions are implemented. The general form of a class declaration is:

The class body contains the declaration of variables and functions. These functions and variables are collectively called as class members. They are usually grouped under two sections. namely, private and public to denote which of the members are private and which of them are public. The keywords private and public are known as visibility labels.

Private: The class members that have been declared as private can be accessed only from within the class. Data hiding is achieved through this. Public: public members can be accessed from outside the class also.

The variables declared inside the class are known as data members and the functions are known as member functions. Only the member functions can have access to the private data members and private functions. However, the public members (both functions and data) can be accessed from outside the class. This is illustrated in Fig. below.

Data hiding in classes:

Simple class example

Class Shapes {

int side; float a ; public: void area(); void peri() ; };

// variable declaration // private by default

// functions declaration // using prototype // ends with semicolon

Creating Objects

Two ways of creating Objects are:

Shapes triangle, square;

// memory for triangle, square, is created.

creates variables triangle, square of type Shapes. In C++ the class variables are known as objects. Therefore. Triangle is called an object of type Shapes.

Objects can also be created when a class is defined by placing their names immediately after the closing brace, as we do in the case of structures. That is to say the definition class Shapes { .....

} triangle, square; would create the objects triangle, square of type Shapes.

Accessing Class Members The private data of a class can be accessed only through the member functions of that class, The main() cannot contain statements that access data directly. The following is the format for calling a member function:

For example. the function call Statement:

square.area(5);

is valid and assigns the value 5 to side of the object square

A member function can be invoked only by using an object (of the same class). The statement : Similarly, the statement square.side = 5; // not valid. area(5); // is not valid.

is also illegal Although square is an object of the type Shapes to which side belongs, the side (declared private) can be accessed only through a member function and not by the object directly.

Example: class xyz { int x; int y; public: int z; };

xyz p ; p.x = 0; p.z = 10 // error. .x is private // Ok, z is public

Member functions can be defined in two places:

Outside the class definition. Inside the class definition.

Outside the Class Definition They should have a function header and a function body. The general form of a member function definition is:

The label class-name:: tells the compiler that the function function-name belongs to the class class-name. That is. the scope of the function is restricted to the class- name. The symbol is called the scope resolution operator. For instance, consider the member functions area() and perimeter():.

void Shapes :: area(int s) { side = s; float a= s*s; cout << a; }

Inside the Class Definition Another method of defining a member function is to replace the function declaration by the actual function definition inside the class. For example. we could define the Shapes class as follows; Class Shapes {

int side; float a ; public: void area(int s);

// variable declaration // private by default

// functions declaration

// behaves like an inline function void area(int s) { side = s; float a= s*s; cout << a; } // definition inside the class

};

An example for a C++ program /* simple C++ program to accept details of a product and display */

#include<iostream.h>

#include<conio.h>

class product

int number; // private by default float cost; // private by default

public:

void getdata(int a, float b); // prototype decl'n

// func defined inside a class

void putdata(void)

cout << "number :" << number << endl; cout << "cost :" << cost <<endl; }

};

/* **** member function defn outside class**** */

void product :: getdata(int a, float b)

number = a; //private variables cost = b; // directly used }

// .....main program....

void main()

product x; // creates object x cout << "\nobject x" << endl; x.getdata(100, 299.95); //call member function x.putdata();

product y; //creates object y cout << "\nobject y" << endl;

y.getdata(200, 175.50); y.putdata(); }

Static data members and Static member functions:

1. When you precede a member variable's declaration with static, you are telling the compiler that only one copy of that variable will exist and that all objects of the class will share that variable. 2. All static variables are initialized to zero before the first object is created. 3. No matter how many objects of a class are created, only one copy of a static data member exists. Thus, all objects of that class use that same variable.

4. When you declare a static data member within a

class, you are not defining it. (That is, you are not allocating storage for it.) Instead, you must provide a global definition for it elsewhere, outside the class. This is done by re-declaring the static variable using the scope resolution operator to identify the class to which it belongs. This causes storage for the variable to be allocated. (Remember, a class declaration is simply a logical construct that does not have physical reality.)

/* static data member */

#include<iostream.h> #include<conio.h>

class product

static int count; int number;

public:

void getdata(int a) {

number = a; count++; }

void getcount(void)

cout << "count =" << count <<endl; // cout << "number =" << number <<endl; }

};

int product :: count ; // def of a static member void main()

product a, b, c; //count is initialized to 0 clrscr();

a.getcount(); // display count b.getcount(); c.getcount();

a.getdata(5); // get data into a b.getdata(6); c.getdata(7);

cout << endl << "after reading data " << endl;

a.getcount(); b.getcount(); c.getcount(); getch();

The static variable count is initialized to zero when the objects are created. The count is incremented whenever the data is read into an object. Since the data is read into objects three times, the variable count is incremented three times, Because there is only one copy of count

shared by all the three objects, all the three output statements cause the value 3 to be displayed.

Static member function

Like static member variable, we can also have static member functions. A member function that is declared static has the following properties:

A static function can have access to only other static members (functions or variables ) declared in the same class. A static member function can be called using the class name (instead of its objects) as follows: class-name :: function-name ; Program below illustrates the implementation of these characteristics. The static function showcountO displays the number of objects created till that moment. A count of number of objects created is maintained by the static variable count. The function showcode() displays the code number of each object.

/* static member function */

#include<iostream.h> #include<conio.h> class test {

int code;

static int count; // static variable public: void setcode(void) {

code = ++count;

void showcode(void) { cout << "object number :"<< code<< endl; }

static void showcount(void) // static member function { cout << "count = " << count << endl; }

};

int test :: count;

void main()

test t1 , t2;

clrscr();

t1.setcode(); t2.setcode();

test :: showcount(); // accessing static fun

test t3; t3.setcode();

test :: showcount();

t1.showcode(); t2.showcode(); t3.showcode();

getch(); }

Constructor

a constructor for a class is needed so that the compiler automatically initializes an object as soon as it is created without explicitly calling any function for the same. A class constructor, if defined, is called whenever a program creates an object of that class.

A constructor is a special member function whose task is to initialize the objects of its class. The constructor is invoked whenever an object of it associated c1ass is created. It a called constructor because it constructs the values of data members of the class.

A constructor is defined like any other member function. However, It has same name as the name of the class it belongs to It does not have any return type (not even void)

Example:

class abc

{ private:

int i; public:

int j, k;

abc() {

//constructor (same name as class, i.e. abc) //no return type

i=0; j=0;k=0; } ..... ..... }; In this example, constructor abc::abc() was defined inline. It may also be defined outline.

Example: class abc { private: int i; public: int j, k;

abc(); .... .... };

//constructor (same name as class, i.e. abc)

abc :: abc() { i=0; j=0;k=0;

//outline definition

Default constructors A constructor may take argument(s). A constructor taking no argument(s) is known as default constructor. If the programmer does not provide any constructor to a class, the compiler automatically provides one with no argument(s). Default constructor provided by the compiler does nothing more than initializing the data members with dummy values. However, if a constructor is defined for the class the default constructor is no more available, it goes into hiding. Example: class abc { private: int i; public: int j, k; //no explicit constructor defined

};

int main() { abc c; //create an instance c of class abc; valid the constructor //abc() is provided by the compiler }

Parametrized constructors A constructor may also have parameter(s) or argument(s), which can be provided at the time of creating an object of that class. Example:

class abc { private: int i; public: int j, k;

abc(int aa, int bb, int cc);

//constructor with //parameters aa, bb and cc

{ i = aa ; j = bb ; k = cc ; } }; int main() { abc abc1(5, 8, 10) ; //create an instance abc1 of class abc; //initialize i, j, and k with 5, 8, and //10 respectively abc abc2(100, 200, 300); //create an instance abc2 of class abc; //initialize i, j, and k with 100, 200, //and 3000 respectively }

Evidently, with parametrized constructor, the correct number and valid argument values must be passed to it at the time of object instantiation. This can be done in two different ways in C++. Implicit call: calling the constructor without mentioning its name. Explicit call: calling the constructor by mentioning its name explicitly. Example: class abc { private: int i; public: int j, k; abc(int aa, int bb, int cc); //constructor with //parameters aa, bb and cc { i = aa ; j = bb ; k = cc; }

}; int main() { abc abc1(5, 8, 10); //implicit call:constructors has not //been called by its name

abc abc2 = abc(100, 200, 300); //explicit call to the constructor of //abc }

Copy constructors A copy constructor is a constructor of the form classname (classname & ). The compiler will use the copy constructor whenever you initialize an instance using values of another instance of same type. Example: student st1; // default constructor used

student st2 = st1; // copy constructor used If a copy constructor is not defined explicitly, the compiler automatically, creates it and it is public. However, the programmer may define his/her own copy constructor for the class in which case the default copy constructor becomes unavailable. A copy constructor takes a reference to an object of the same class as argument. Example: class student { int rollno; float marks; public : student (int a, float b) // constructor { rollno = a ; marks = b } student(student &s ) // copy constructor { rollno = s.rollno; marks = s.marks + 5;

} }; These constructors may be used as follows: student s1(5, 78.5); //constructor used to initialize s1.rollno to //5 and s1.marks to 78.5 student s2(s1); //copy constructor used to initialize //s2.rollno to 5 and s2.marks to //s1.marks+5, i.e. 78.5+5=83.5

/* program to implement parameterized constr, default constr, */

#include<iostream.h> #include<conio.h>

class complex

public: float x, y ; complex() { } // default constr

complex(float a)

//constr with one arg

x= y = a;

complex(float real, float imag) //constr-two args {

x= real; y= imag;

complex sum(complex, complex); void show(complex); };

complex sum(complex c1, complex c2)

{ complex c3; c3.x = c1.x + c2.x; c3.y = c1.y + c2.y; return(c3); }

void show(complex c)

cout << c.x << " +j"<< c.y << "\n";

int main()

complex A(2.7, 3.5); //define and initialize complex B(1.6); complex C; clrscr(); C = sum(A, B); cout << "A = "; show(A); cout << "B = "; show(B); cout << "C = "; show(C); //define and initialize //define

// another way to give initial values

complex P, Q, R;

//define p, q, r

P = complex(2.5, 3.9); //initialize P

Q = complex(1.6, 2.5); //initialize Q R = sum(P, Q);

cout << "\n"; cout << "P ="; show(P); cout << "Q ="; show(Q); cout << "R ="; show(R);

return 0;

Destructors A destructor is a function that automatically executes when an object is destroyed. A destructor function gets executed whenever an instance of the class to which it belongs goes out of existence. The primary use of the destructor function is to release space. Rules for writing destructor function: 1. A destructor function name is the same as that of the class it belongs except that the first character of the name must be a tilde(~). 2. It is declared with no return type. 3. It cannot be declared static, const or volatile 4. It takes no arguments and therefore cannot be overloaded 5. It should have public access in the class declaration.

//Destructor example

#include<iostream.h> #include<conio.h>

class demo { public: demo() { cout<<"constructor..."<<endl<<endl; } //constructor

~demo() {

//destructor

cout<<"destructor...."<<endl<<endl; cout<<" object is destroyed"<<endl<<endl; }

};

void f(void) { demo d; //constructor call cout << "object d is created" <<endl<<endl;

cout<<"exiting f()..."<<endl<<endl;

} //destructor call for d

int main()

{ clrscr(); demo dd; //constructor call

cout << "object dd is created" <<endl<<endl;

cout<<"calling f()..."<<endl<<endl;

f();

cout<<"returned to main()...."<<endl;

return 0;

} //destructor call for dd

Constant object and constant member function: The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.

Declaring a member function with the const keyword specifies that the function is a "read-only" function that does not modify the object for which it is called. To declare a constant member function, place the const keyword after the closing parenthesis of the argument list. The const keyword is required in both the declaration and the definition. A constant member function cannot modify any data members or call any member functions that are not constant

//const member functions and const objects

#include<iostream.h> #include<conio.h>

class point { private: int x; int y; public:

point(int xx =0 , int yy=0) //constructor { x=xx; y=yy; }

int getx(void)const

// const member function

{ return x; }

int gety(void)const { return y; }

//const member function

int tx(int dx) { x=x+dx; return x; }

// non- const member function

};

int main() {

const point a(20,40); point b(30,60); clrscr(); cout<<a.getx()<<endl; //legal cout<<a.gety()<<endl; //legal

//a.tx(10); //illegal, since a is a const object and

//tx() is non const function

cout<<b.getx()<<endl; //legal cout<<b.gety()<<endl; //legal

cout <<b.tx(20)<<endl; //legal, since b is non-constant object

return 0;

this keyword

The members functions of every object have access to a sort of magic pointer named this , which points to the object itself. Thus any member function can find out the address of the object of which it is a member.

// demonstration of this key word

# include<iostream.h> #include<conio.h>

class sample { private: char ch[10]; public:

void reveal( )

cout<<"my object's address is "<< this;

};

void main( ) { sample s1,s2,s3; s1.reveal( ); s2.reveal( ); s3.reveal( ); }

The main( ) program in this example creates three objects of type sample, then asks each object to print its address, using the reveal( ) member function. This function prints out the value of the this pointer.

Accessing Member data with this When you call a member function, it comes into existence with the value of this set of the address of the object for which it was called. The this pointer can be treated like any other pointer to an object and can thus be used to access the data in the object to points.

/* this */

#include<iostream.h> #include<conio.h>

class sample { private: int a; public: void set() { a=123;

//or

this->a=123; }

void get()

{ cout <<this->a;

};

void main()

sample s1; clrscr(); s1.set(); s1.get();

Operator overloading C++ tries to make the user-defined data types behave in much the same was as the built-in types. For instance, C++ permits us to add two variables of user-defined types with the same syntax that is applied to the basic types. This means that C++ has the ability to provide the operators with a special meaning for a data type. The mechanism of giving such special meanings to an operator is known as operator overloading. The following operators cannot be overloaded:

access operators of class member ( . and .*) scope resolution operator size operator conditional operator ( :: ) (sizeof) ( ?: )

The general form of an operator functions is: <Returntype> classname:: operator op (<arg-list>)

{ Function body // task defined }

The process of overloading may be summarized in the following steps: 1. First, create a class that defines the data type that is to be used in the overloading peration. 2. Declare the operator function operator op( ) in the public part of the class. It may be either a member function or a friend function. 3. Define the operator functions to implement the required operations. Overloaded operator functions can be invoked by expressions such as op x or x op for unary operators and

x op y

for binary operators

Similarly, the expression x op y would be interpreted as either x.operator op(y) operator op (x,y) in case of member functions, or in case of friend functions.

RULES FOR OVERLOADING OPERATORS 1. Only existing operators can be overloaded. New operators cannot be created. 2. The overloaded operator must have at least one operand that is of userdefined type. 3. We cannot change the basic meaning of an operator. That is we cannot redefine the plus(+) operator to subtract one value from the other.

4. Overloaded operators follow the syntax rules of the original operators,. that cannot be overridden. 5. There are some operators that cannot be overloaded. 6. Unary operators, overloaded by means of a member function, take no explicit arguments and return no explicit values. But, those overloaded by means of a friend function take one reference argument (the object of the relevant class). 8. Binary operators overloaded through a member function take on explicit argument and those, which are overloaded through a friend function take two explicit arguments. 9. When using binary operators overloaded through a member function, the left-hand operand must be and object of the relevant class. 10. Binary arithmetic operators such as +, -, *, and /must explicitly return a value. They must not attempt to change their own arguments.

Operators that cannot be overloaded Sizeof . .* :: ?: size of operator Membership operator Pointer-to-member operator Scope resolution operator conditional operator

Overloading Unary operator

The word operator is a keyword and is preceded by the return type void. The operator to be overloaded is written immediately after the keyword operator. This declaration informs the compiler to invoke the overloaded function ++ whenever the unary increment operators prefixed or post fixed to an object of the index class.

Eg: unary minus operator minus operator, when used as unary takes just one operand. We know that this operator changes the sign of an operand when applied to a basic data item. The unary minus when applied to an object should change the sign of each of its data items.

//Overloading unary minus operator.

#include <iostream.h> #include<conio.h>

class space { int x , y ,z;

public: void getdata (int a, int b, int c); void display (void);

void operator ( ) //overload unary minus };

void space : : getdata (int a, int b, int c) { x=a; y=b; z=c; }

void space : : display (void) { count << x << ; count << y << ; count << z << \n; }

void space : : operator- ( ) // Defining operator ( ) { x = - x; y = -y; z = -z; }

void main () { space s;

s.getdata (10,-20, 30); cout << s : ;

s.display ( ) ;

-s; cout << s : ; s.display ( ) ; }

//activates operator ( )

Overloading binary operators: //Operator overlaoding of binary + and // operator+() and operator-() functions are member functions

#include<iostream.h> #include<conio.h>

class complex { private: int real,imag; public:

complex(int xx=0,int yy=0) //constructor { real = xx;

imag = yy; }

complex operator +(complex c) //note the single argument { complex temp; temp.real = real + c.real; temp.imag = imag + c.imag; return temp; }

complex operator (complex c) { complex temp; temp.real = real - c.real; temp.imag = imag - c.imag; return temp; }

void show(void) { cout<<endl<< real<<" +j"<<imag<<endl; } };

void main() {

clrscr(); complex a(10,20) , b(30,40) , c, d , e; c = a + b; d = a - b; c.show(); d.show(); } As a rule, in overloading of binary operators, the left-hand operand is used to invoke the operator functions and the right-hand operand is passed as an argument.

Let us look at the statement that invokes this function: c =a + b ; //invokes operator + ( ) function

A member function can be invoked only by an object of the same class. Here, the object a takes the responsibility of invoking the functions and b plays the role of an argument that is passed to function. The above statement is equivalent to c = a .operator +(b) ; //usual function call syntax Therefore, in the operator +( ) function, the data members of a are accessed directly and the data members of b (that is passed as an argument) are accessed using the dot operator. Thus, both the objects are available for the function. For example, in the statement temp.real = real + c.real; c.real refers to the object b and real refers to the object a. temp.real has been created specially to hold the results of addition of a and b. The function returns the complex temp to be assigned to c.

Friend functions The main concept of the object oriented programming are data hiding and data encapsulation. Whenever data variables are declared in a private category of a class these members are restricted from accessing by nonmember functions. To access a private data member by a non-member function is to change a private data member to a public group. When the private or protected data member is changed to a public category, it violates the whole concept of data hiding and data encapsulation. To solve this problem, a friend function can be declared to have access to these data members. Friend is a special mechanism for letting non-member functions access private data. A friend function may be declared or defined within the scope of a class definition. The keyword friend inform the compiler that it is not a member function of the class. The general form is friend return_type user_function_name (parameters); where friend is a keyword used as function modifier.

/* friend to a class*/

#include<iostream.h> #include<conio.h>

class alpha { private:

int x; public: void getdata();

friend void display(alpha a); //friend indicates that display is a non-member //function

};

void alpha::getdata() { cout << " enter a value for x: "<< endl; cin >> x; }

void display(alpha a) { cout << a.x; }

void main() { alpha obj; clrscr(); obj.getdata(); display(obj); getch();

You might also like