module iii

92
OPERATOR OVERLOADING The mechanism of giving special meanings to an operator is known as operator overloading. It provides a flexible way for the creation of new definitions for most of the C++ operators. We can overload all C++ operators except the following: Class member access operators ., * Scope resolution operator :: Size operator sizeof Conditional operator ? Although the semantics of an operator can be extended, we cannot change its syntax, the grammatical rules that govern its use such as the number of operands, precedence and associativity. DEFINING OPERATOR OVERLOADING To define an additional task to an operator we use a special function called operator function which describes the task. The general form is return_type classname :: operator op(arg list) { function body } return type type of value returned by the specified operation. op the operator being overloaded. operator - op is preceded by the keyword operator. 1

Upload: akash-raj

Post on 21-Jul-2016

14 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Module III

OPERATOR OVERLOADING

The mechanism of giving special meanings to an operator is known as operator overloading.

It provides a flexible way for the creation of new definitions for most of the C++ operators.

We can overload all C++ operators except the following:

Class member access operators ., *

Scope resolution operator ::

Size operator sizeof

Conditional operator ?

Although the semantics of an operator can be extended, we cannot change its syntax, the grammatical rules that govern its use such as the number of operands, precedence and associativity.

DEFINING OPERATOR OVERLOADING

To define an additional task to an operator we use a special function called operator function which describes the task.

The general form is

return_type classname :: operator op(arg list)

{

function body

}

return type – type of value returned by the specified operation.

op – the operator being overloaded.

operator - op is preceded by the keyword operator.

operator op – function name.

Operator functions must be either member functions or friend functions.

The basic difference between them is that a friend function will have only one argument for unary operators and two for binary operators.

A member function has no argument for unary operators and one for binary operators.

1

Page 2: Module III

Operator functions are declared in the class using prototype as follows:

vector operator+(vector); //vector addition

vector operator-(); //unary minus

friend vector operator+(vector, vector);

//vector addition

friend vector operator-(vector); //unary minus

The process of overloading involves the following steps:

Create a class that defines the data type that is to be used in the overloading operation.

Declare the operator function operator op() in the public part of the class. It may be either a friend function or a member function.

Define the operator function to implement the required operations.

For unary operators overloaded operator functions can be invoked by expressions such as

op x

or

x op

For binary operators overloaded operator functions can be invoked by expressions such as

x op y

OVERLOADING unary operator

Consider the unary minus operator.

A unary minus changes the sign of an operand when applied to a basic data item.

We will see how to overload this operator so that it can be applied to an object.

The unary minus when applied to an object should change the sign of each of its data items.

2

Page 3: Module III

OVERLOADING unary minus

#include<iostream.h>

class space

{

int x;

int y;

public:

void getdata( int a, int b);

void display();

void operator –();

};

void space ::getdata(int a, int b)

{

x = a; y = b;

}

void space ::display()

{

cout<<x;

cout<<y;

}

void space :: operator –()

{

x = -x;

y = -y;

}

void main()

{

3

Page 4: Module III

space S;

S.getdata( 10, -20);

cout<<“S : “;

S.display();

-S;

cout<<“S : “;

S.display();

}

OVERLOADING unary minus using friend function

It is possible to overload a unary minus using a friend function as follows:

friend void operator –(space &s);

//declaration

void operator – (space &s) //definition

{

s.x = -s.x;

s.y = -s.y;

}

OVERLOADING binary operator

We can add two complex numbers A and B using a function as

C = sum(A, B);

The functional notation can be replaced by a natural looking expression

C = A + B;

4

Output

S : 10 -20

S : -10 20

Page 5: Module III

This is done by overloading the + operator using an operator+() function.

OVERLOADING + operator

#include<iostream.h>

class complex

{

float x;

float y;

public:

complex() { }

complex( float real, float imag)

{

x = real ;

y = imag;

}

complex operator +(complex );

void display();

};

complex complex::display()

{

cout<<x<<“+j”<<y;

}

complex complex :: operator +(complex c)

{

complex temp;

temp.x = x + c.x;

temp.y = y + c.y;

return( temp);

}

5

Page 6: Module III

void main()

{

complex C1, C2, C3;

C1 = complex(2.5, 3.5);

C2 = complex(1.6, 2.7);

C3 = C1 + C2; C3 = C1.operator +(C2);

cout<<“C1 =“<<C1.display();

cout<<“C2 =“<<C2.display();

cout<<“C3 =“<<C3.display();

}

OVERLOADING binary operator using friend function

It is possible to overload a binary operator using a friend function.

The only requirement is that a friend function requires two arguments to be explicitly passed to it.

friend complex operator +(complex, complex);

//declaration

complex operator +(complex a, complex b)

{

complex temp;

temp.x = a.x + b.x;

temp.y = a.y + b.y;

return( temp);

}

In this case the statement

C3 = C1+ C2;

is equivalent to

C3 = operator+(C1, C2);

6

Page 7: Module III

In most cases we get the same results by the use of either a friend function or a member function.

There are certain situations where we would like to use a friend function rather than a member function.

Consider a situation where we need to use two different types of operands for binary operator.

Say, one an object and another a built-in type data as shown

A = B + 2;

This will work for a member function. But the statement

A = 2 + B;

will not work.

This is because the left-hand operand which is responsible for invoking the member function should be an object of the same class.

However friend functions allows both approaches.

This is because that an object is not needed to invoke a friend function.

Thus we can use a friend function with a built-in type data as left-hand operand and an object as the right-hand operand.

RULES FOR OVERLOADING operators

Only existing operators can be overloaded. New operators cannot be created.

The overloaded operator must have at least one operand that is of user-defined type.

We cannot change the basic meaning of an operator.

Overloaded operators follow the syntax rules of the original operators.

Some operators cannot be overloaded.

We cannot use friend functions to overload certain operators. ( =, (), [ ], ->).

Unary operator overloaded using

member function à no arguments

friend function à one argument

Binary operator overloaded using

member function à one argument

friend function à two arguments

7

Page 8: Module III

When using binary operators overloaded through a member function, the left-hand operand must be an object of the relevant class.

Binary arithmetic operators *, +, -, / must explicitly return a value.

TYPE CONVERSIONS

When constants and variables of different types are mixed in an expression, C applies automatic type conversions.

The type of data to the right of an assignment operator is automatically converted to the type of the variable on the left.

What happens when they are user-defined data types?

Consider the statement that adds two objects and assigns the result in third object.

v1 = v2 + v3;

When the objects are of the same class type, the operations of addition and assignment are carried out smoothly.

This is not the case when one of the operands is a built-in data and other an object or if they belongs to two different classes.

Since user-defined data types are defined by us, the compiler does not support automatic type conversions of such data types.

We must therefore design conversion routines by ourselves if such operations are required.

Three types of situations may arise in the data conversions between incompatible types.

TYPE CONVERSIONS

1. Conversion from basic type to class type.

2. Conversion from class type to basic type.

3 Conversion from one class type to another class type.

Basic to Class Type

The conversion from basic to class type is accomplished easily with the help of constructors.

Consider the following constructor:

string :: string( char *a)

{

length = strlen(a);

P = new char[length+1];

8

Page 9: Module III

strcpy(P, a);

}

This constructor builds a string type object from char* type variable a.

The variables length and p are data members of the class string.

Once this constructor has been defined in the string class, it can be used for conversion from char* to string type

E.g. :-

string s1, s2;

char* name1 = “ IBM PC”;

char* name2 = “ Apple Computers”;

s1 = string(name1);

s2 = name2;

The statement

s1 = string(name1);

first converts name1 from char* type to string type and then assigns the string type values to the object s1.

The statement

s2 = name2;

also does the same job by invoking the constructor implicitly.

Consider another example of converting int type to class type.

class time

{

int hrs;

int mins;

public:

time( int t)

{

hrs = t / 60;

mins = t % 60;

9

Page 10: Module III

}

};

time T1;

int duration = 85;

T1 = duration;

The constructors used for the type conversion take a single argument whose type is to be converted.

Class to Basic Type

The constructor functions do not support this operation.

But C++ allows us to define an overloaded casting operator that would be used to convert a class type data to a basic type.

The overloaded casting operator function is referred to as conversion function.

The general form is :

operator typename()

{

……..

……..

……..

}

This function converts a class type data to typename

For e.g. , the operator double() converts class objects to type double, the operator int() converts class objects to type int.

vector :: operator double()

{

double sum = 0;

for( int i=0; i<size; i++)

sum = sum + v[i] * v[i];

return sqrt(sum);

}

10

Page 11: Module III

This function converts a vector to the corresponding scalar magnitude.

The operator double() can be used as follows:

double length = double( v1);

or

double length = v1;

The casting operator function should satisfy the following conditions:

1. It must be a class member.

2. It must not specify a return type.

3. It must not have any arguments.

Since it is a member function, it is invoked by the object.

One Class to Another Class Type

Consider the statement

objX = objY;

objX is an object of class X and objY is an object of class Y.

Class Y type data is converted to the class X type data and the converted value is assigned to the objX.

The conversion take place from class Y to class X. Y is the source class and X is the destination class.

Such conversions between objects of different classes can be carried out by either a constructor or a conversion function.

For the casting operator function

operator typename()

the typename may be a built-in type or user-defined type.

In the case of conversions between objects the typename refers to the destination class

When a class needs to be converted the casting operator function can be used in the source class.

The conversion take place on the source class and the result is given to the destination class object.

The single argument constructor function converts the argument’s type to the class type of which it is a member.

11

Page 12: Module III

This implies that the argument belongs to the source class and is passed to the destination for conversion.

This makes it necessary that the constructor is placed in the destination class.

objX = objY // Y is a source class

Class Y

Converted value of type

(source class)

Class X Class Y

Argument of type Y

(destination class)

INHERITANCE

C++ strongly supports the concepts of reusability.

The C++ classes can be reused in several ways.

Once a class has been written and tested, it can be used to create new classes reusing the properties if existing ones.

The mechanism of deriving a new class from an old one is called inheritance or derivation.

The old class is referred to as the base class and the new one is called the derived class or subclass.

A class can inherit some or all the traits from the base class.

A class can inherit from more than one class or from more than one level.

A derived class with only one base class is called single inheritance.

A derived class with multiple base classes is called multiple inheritance.

Traits of one class may be inherited by more than one class – hierarchical inheritance

The mechanism of deriving a class from another derived class is called multilevel inheritance.

12

Casting operato

r function

Constructor

function

Data acce

ss function

s

Page 13: Module III

DEFINING DERIVED CLASSES

The general form is:

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

{

…….. //

……..// members of the derived class

……..//

};

The colon indicates that the derived-class-name is derived from the base-class-name.

The visibility mode is optional, if present, may be either private or public.

The default visibility mode is private.

The visibility mode specifies whether the features of the base class are privately derived or publicly derived.

class ABC : private XYZ // private derivation

{

members of ABC

};

class ABC : public XYZ // public derivation

{

members of ABC

};

class ABC : XYZ // private derivation by default

{

members of ABC

};

While privately inheriting, public members of the base class become private members of the derived class.

Therefore public members of the base class can only be accessed by the member functions of the derived class.

13

Page 14: Module III

They are inaccessible to the objects of the derived class.

While publicly inheriting, public members of the base class become public members of the derived class.

They are accessible to the objects of the derived class.

In both the cases, the private members are not inherited

Single inheritance – public

#include<iostream.h>

class B

{

int a;

public:

int b;

void get_ab();

int get_a();

void show_a();

};

class D : public B

{

int c;

public:

void mul();

void display();

};

void B :: get_ab()

{

a=5; b=10;

}

int B :: get_a()

14

Page 15: Module III

{

return a;

}

void B :: show_a()

{

cout<<“a=“<<a;

}

void D :: mul()

{

c = b * get_a();

}

void D :: display()

{

cout<<“a=“<<get_a();

cout<<“b=“<<b;

cout<<“c=“<<c;

}

void main()

{

D d;

d.get_ab();

d.mul();

d.show_a();

d.display();

d.b = 20;

d.mul();

d.display();15

Page 16: Module III

}

Single inheritance – private

#include<iostream.h>

class B

{

int a;

public:

int b;

void get_ab();

int get_a();

void show_a();

};

class D : private B

{

int c;

public:

void mul();

void display();

};

void B :: get_ab()

{

16

Outputa = 5a = 5

b = 10c = 50

a = 5b = 20c = 100

Page 17: Module III

a=5; b=10;

}

int B :: get_a()

{

return a;

}

void B :: show_a()

{

cout<<“a=“<<a;

}

void D :: mul()

{

get_ab();

c = b * get_a();

}

void D :: display()

{

show_a(); // outputs a

cout<<“a=“<<get_a();

cout<<“b=“<<b;

cout<<“c=“<<c;

}

void main()

{

D d;

//d.get_ab(); won’t work

d.mul();

//d.show_a(); won't work

17

Page 18: Module III

d.display();

//d.b = 20; won't work

d.mul();

d.display();

}

MAKING PRIVATE MEMBERS INHERITABLE

C++ provides a third visibility modifier, protected which serve a limited purpose inheritance.

A member declared as protected is accessible by the member functions within the class and any class immediately derived from it.

It cannot be accessed by functions outside these two classes.

class alpha

{

private :

…….. // visible to member functions within the class

protected:

……..// visible to member functions of its own and derived class

public :

……..// visible to all functions within the program

};

When protected member is inherited in public mode, it becomes protected in the derived class

18

Outputa = 5

b = 10c = 50

a = 5b = 10c = 50

Page 19: Module III

It is accessible to the member functions in the derived class.

It is also ready for further inheritance.

When protected member is inherited in private mode, it becomes private in the derived class

It is accessible to the member functions in the derived class.

It is not ready for further inheritance.

It is also possible to inherit a base class in protected mode.

In protected derivation both public and protected members of the base class becomes protected members of the derived class.

Multilevel inheritance

A derived class with multilevel inheritance is declared as follows:

class A {……..};

class B : public A {……};

class C : public B {……};

This process can be extended to any number of levels

Assume that the test results of a batch of students are stored in three different classes.

Class student stores roll no, class test stores the marks obtained in two subjects and class result contains the total marks obtained in the test.

The class result can inherit the details of the marks in the test and the roll no through multilevel inheritance.

#include<iostream.h>

class student

{

protected:

int rollno;

public:

void getnum(int);

void putnum();

};

void student :: getnum(int a)

{

19

Page 20: Module III

roll_no = a;

}

void student :: putnum(int a)

{

cout<<“rollno”<<rollno;

}

class test : public student

{

protected:

float sub1;

float sub2;

public:

void getmarks(float, float);

void putmarks();

};

void test :: getmarks(float x, float y)

{

sub1 = x;

sub2 = y;

}

void test ::putmarks()

{

cout<<“sub1=“<<sub1;

cout<<“sub2=“<<sub2;

}

class result : public test

{

20

Page 21: Module III

float total;

public:

void display();

};

void result :: display()

{

total = sub1 + sub2;

putnum();

putmarks();

cout<<“total=“<<total;

}

void main()

{

result student;

student.getnum(111);

student.getmarks(75.0,59.5);

student.display();

}

Multiple inheritance

A class can inherit the attributes of two or more classes – multiple inheritance.

21

Outputrollno = 111sub1 = 75.0sub2 = 59.5

total = 134.5

Page 22: Module III

Multiple inheritance allows us to combine the features of several existing classes.

The general form is:

class D : visibility B1, visibility B2…….

{

body of D

};

#include<iostream.h>

class M

{

protected:

int m;

public:

void getm(int);

};

void M :: getm(int x)

{

m = x;

}

class N

{

protected:

int n;

public:

void getn(int);

};

void N:: getm(int y)

{

n = y;

22

Page 23: Module III

}

class P : public M, public N

{

public:

void display();

};

void P :: display()

{

cout<<“m=“<<m;

cout<<“n=“<<n;

cout<<“m*n =“<<m*n;

}

void main()

{

P p;

p.getm(10);

p.getn(20);

p.display();

}

Ambiguity resolution in inheritance

We may face a problem in multiple inheritance, when a function with the same name appears in more than one base class.

Consider the following two classes.

class M23

Outputm = 10n = 20

m*n = 200

Page 24: Module III

{

public:

void display()

{

cout<<“class M”;

}

};

class N

{

public:

void display()

{

cout<<“class N”;

}

};

The problem is which display() function is to be used by the derived class.

This problem can be solved by defining a named instance within the derived class, using the class resolution operator with the function as shown below:

class P : public M, public N

{

public:

void display()

{

M::display();

}

};

VIRTUAL BASE CLASSES

24

Page 25: Module III

Consider a situation where all the three kinds of inheritance – multiple, multilevel and hierarchical inheritance are involved.

The child inherits traits of grandparent via two separate paths.

It can also inherit directly as shown.

This type of inheritance might pose some problems.

All the public and protected members of the grandparent are inherited into the child twice, via perent1 and parent2.

This duplication of the inherited members can be avoided by making the common base class as virtual base class.

When a class is made virtual base class, C++ takes necessary care to see that only one copy of that class is inherited, regardless of how many inheritance paths exist between the virtual base class and a derived class.

class A // grandparent

{

……

};

class B1 :virtual public A //parent1

25

Grandparent

Parent 1 Parent 2

Child

Page 26: Module III

{

……

};

class B2 : public virtual A //parent2

{

……

};

class C: public B1, public B2 //child

{

…… //only one copy of A will be inherited

};

ABSTRACT CLASSES

An abstract class is one that is not used to create objects.

An abstract class is designed only to act as a base class.

Constructors in derived classes

As long as no base class constructor takes any arguments, the derived class need not have a constructor function.

If the base class contains a constructor with one or more arguments, then the derived class must have a constructor and pass arguments to the base class constructors.

When both derived and base classes contains constructors, the base constructor is executed first and then the constructor in the derived class.

In the case of multiple inheritance the base classes are constructed in the order in which they appear in the declaration of the derived class.

In multilevel inheritance the constructors will be executed in the order of inheritance.

The derived class have the responsibility of supplying the initial values to its base classes.

We supply the initial values that are required by all the classes together, when a derived class object is declared.

C++ provides a special argument passing mechanism for such situations.

26

Page 27: Module III

The constructors of the derived class receives the entire list of values as its arguments and passes them on to the base constructors in the order in which they are declared in the derived class.

The base constructors are called and executed before executing the statements in the body of the derived constructor.

The general form of defining a derived constructor is:

Derived-constructor (Arglist1, Arglist2,… ArglistN, ArglistD) :

base1(arglist1),

base2(arglist2),

……..

baseN(arglistN)

{

body of derived constructor

}

The header line of the derived constructor contains two parts separated by a colon (:) .

The first part provides the declaration of arguments that are passed to the derived constructor.

The second part lists the function calls to the base constructors.

E.g. :-

D( int a1, int a2, float b1, float b2, int d1) :

A(a1, a2), //call to constructor A

B(b1, b2) //call to constructor B

{

d = d1; //executes its own body

}

The constructor D() may be invoked as follows:

D objD( 5, 12, 2.5, 7.54, 30);

27

Page 28: Module III

Member classes: Nesting of classes

C++ supports another way of inheriting properties of one class into another.

This approach takes the view that an object can be a collection of many other objects.

A class can contain objects of other classes as its members.

class alpha {……..};

class beta{……..};

class gamma

{

alpha a;

beta b;

……..

};

All objects of gamma class will contain the objects a and b. This kind of relationship is called containership or nesting.

An independent object is created by its constructor.

A nested object is created in two stages.

First the member objects are created using their respective constructors and then the ordinary members are created.

So constructors of all the member objects must be called before its own constructor body is executed.

This is accomplished with the help of an initialization list in the constructor of the nested class.

class gamma

{

alpha a;

beta b;

public:

gamma(arglist) : a(arglist1), b(arglist2)

{

28

Page 29: Module III

constructor body

}

};

E.g.:-

gamma(intx, int y, float z) : a(x), b(x, z)

{

Assignment section (for ordinary members)

}

POINTERS TO OBJECTS

A pointer can point to an object created by a class.

We can declare an object x of the class item and a pointer ptr to x as follows:

item x;

item *ptr = &x;

The pointer ptr is initialized with the address of x.

We can refer to the member functions of item in two ways,

Dot operator and the object

Arrow operator and the object pointer

The statements

x.getdata(10,20);

x.show();

is equivalent to

ptr->getdata(10,20);

ptr->show();

Since *ptr is an alias of x, we can also use the following method:

(*ptr).show();

“this” pointer

C++ uses a unique keyword called this to represent an object that invokes a member function.

29

Page 30: Module III

this is a pointer that points to the object for which this function is called.

For example the function call

A.max();

will set the pointer this to the address of the object A

This unique pointer is automatically passed to a member function when it is called.

The pointer acts as an implicit argument to all the member functions.

We are implicitly using the pointer this when overloading the operators using member functions.

When a binary operator is overloaded using member function, we pass only one argument to the function.

The other argument is implicitly passed using the pointer this.

Another important application of this pointer is to return the object it points to.

The statement

return *this;

inside a member function will return the object that invoked the function

This statement assumes importance when we want to compare two or more objects inside a member function and return the invoking object as a result.

#include<iostream.h>

#include<cstring.h>

class person

{

char name[20];

float age;

public:

person(char*s, float a)

{

strcpy(name, s);

age = a;

}

30

Page 31: Module III

person & greater(person &x)

{

if(x.age >= age)

return x;

else

return *this;

}

void display()

{

cout<<name<<age;

}

};

void main()

{

person P1(“John”, 30), P2(“Ahmed”, 25);

person P = P1.greater(P2);

cout<<“Elder person is :\n”;

P.display();

}

POINTERS TO DERIVED CLASSES

We can use pointers not only to the base class objects but also to the derived class objects.

A single pointer variable can be made to point to objects belonging to different classes.

If B is a base class and D is a derived class then a pointer declared as pointer to B can also be a pointer to D.

31

OutputElder

person is :

John 30

Page 32: Module III

B *cptr;

B b;

D d;

cptr = &b;

we can make cptr to point to the object d as follows:

cptr = &d;

There is a problem in using cptr to access the public members of the derived class D.

Using cptr we can access only those members which are inherited from B and not the members that originally belong to D.

If a member of D has the same name as one of the members of B, then any reference to that member by cptr will always access the base class member.

#include<iostream.h>

class BC

{

public:

int b;

void show()

{

cout<<“b=“<<b;

}

};

class DC : public BC

{

public:

int d;

void show()

{

cout<<“b=“<<b;

32

Page 33: Module III

cout<<“d=“<<d;

}

};

void main()

{

BC *bptr;

BC base;

bptr = &base;

bptr->b = 100;

cout<<“bptr points to base”;

bptr->show();

DC dervd;

bptr = &dervd;

bptr->b = 200;

// bptr->d = 300;

cout<<“bptr points to drvd”;

bptr->show();

DC *dptr;

dptr->d = 300;

cout<<“dptr is derived type ptr”;

dptr->show();

}

33

Outputbptr points to baseb=100bptr points to drvdb=200dptr is derived type ptrb=200d=300

Page 34: Module III

POLYMORPHISM

Polymorphism means one name multiple forms.

We have implemented polymorphism using overloaded functions and operators.

The overloaded member functions are invoked by matching arguments.

This information is known to the compiler at compile time, so the compiler is able to call the appropriate function at compile time itself.

This is called early binding or static binding or compile time polymorphism

Consider a situation where the function name and prototype is same in both base class and derived class.

Since the prototype is the same function overloading does not apply.

We may use the class resolution operator to specify the class while invoking the function with derived class objects.

It would be nice if the appropriate member function could be selected at run time- run time polymorphism.

C++ supports a mechanism known as virtual functions to support run time polymorphism.

At run time when it is known that which appropriate objects are under consideration, the appropriate version of the function is invoked.

Since a function is linked with the class much later after compilation , this process is known as late binding.

VIRTUAL FUNCTIONS

When we use the same function name in both the base and derived class, the function in the base class is declared as virtual.

When a function is made virtual, C++ determines which function to use at run time based on the type of the object pointed by the base pointer.

Thus making the base pointer to point to different objects, we can execute different versions of the virtual function.

#include<iostream.h>

class Base

{

public:

void display()

{

34

Page 35: Module III

cout<<“display base“;

}

virtual void show()

{

cout<<“show base”;

}

};

class Derived : public Base

{

public:

void show()

{

cout<<“show derived”;

}

void display()

{

cout<<“display derived“;

}

};

void main()

{Base b;

Derived d;

Base *bptr;

cout<<“bptr pts to base”;

bptr = &b;

bptr->display();

bptr->show();

35

Page 36: Module III

cout<<“bptr pts to derived”;

bptr = &d;

bptr->display();

bptr->show();

}

RULES FOR VIRTUAL FUNCTIONS

The virtual functions must be members of some class.

They cannot be static members.

They are accessed by using object pointers.

A virtual function can be a friend of another class.

A virtual function in a base class must be defined even though it may not be used

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

We cannot have virtual constructors, but we can have virtual destructors.

A pointer of the derived class type cannot be used to access an object of base class.

When a base pointer points to a derived class, incrementing or decrementing it will not make it to point to the next object of the derived class.

If a virtual function is defined in the base class, it need not be redefined in the derived class.

PURE VIRTUAL FUNCTIONS

The function inside the base class is seldom used for performing any task.

It only serves as a “placeholder”. Such functions are called “do-nothing” functions.

A “do-nothing” function may be defined as follows:

36

Outputbptr points to basedisplay base show basebptr points to deriveddisplay base show derived

Page 37: Module III

virtual void display() = 0;

Such functions are called pure virtual functions.

A pure virtual function is a function declared in a base class that has no definition relative to the base class.

A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class, if that class is not abstract. Classes containing pure virtual methods are termed "abstract" and they cannot be instantiated directly. A subclass of an abstract class can only be instantiated directly if all inherited pure virtual methods have been implemented by that class or a parent class. Pure virtual methods typically have a declaration (signature) and no definition (implementation).

As an example, an abstract base class MathSymbol may provide a pure virtual function doOperation(), and derived classes Plus and Minus implement doOperation() to provide concrete implementations. Implementing doOperation() would not make sense in the MathSymbol class, as MathSymbol is an abstract concept whose behaviour is defined solely for each given kind (subclass) of MathSymbol. Similarly, a given subclass of MathSymbol would not be complete without an implementation of doOperation().

Although pure virtual methods typically have no implementation in the class that declares them, pure virtual methods in C++ are permitted to contain an implementation in their declaring class, providing fallback or default behaviour that a derived class can delegate to, if appropriate.

Pure virtual functions can also be used where the method declarations are being used to define an interface - similar to what the interface keyword in Java explicitly specifies. In such a use, derived classes will supply all implementations. In such a design pattern, the abstract class which serves as an interface will contain only pure virtual functions, but no data members or ordinary methods. In C++, using such purely abstract classes as interfaces works because C++ supports multiple inheritance. However, because many OOP languages do not support multiple inheritance, they often provide a separate interface mechanism.

WORKING WITH FILES

Data is stored in the storage devices in the form of files.

A file is a collection of related data stored in a particular area on the disk.

Programs can be designed to perform read and write operations on these files.

A program typically involves two types of data communications.

Between console unit and the program

Between program and the disk file.

The I/O system of C++ uses file streams as an interface between program and the file.

The stream that supplies data to the program – input stream.

The stream that retrieves data from the program – output stream.37

Page 38: Module III

READ DATA DATA INPUT

WRITE DATA DATA OUTPUT

The input operation involves the creation of an input stream and linking it with the program and the input file.

The output operation involves the creation of an output stream and linking it with the program and the input file.

Classes for file stream operations

ifstream

ofstream

fstream

Opening and closing a file

To use a disk file we need to decide the following things about the file and its intended use:

Suitable name for the file

Data type and structure

Purpose

Opening method

38

Input stream

Disk files

Program

Output stream

Page 39: Module III

For opening a file we must first create a file stream and then link it to the filename.

A file stream can be defined using the classes ifstream, ofstream and fstream that are contained in the header file fstream

The class to be used depends upon whether to read data from a file or write data to it.

A file can be opened in two ways:

Using constructor function of the class

Using member function open() of the class

First method à only one file in the stream

Second method àmanage multiple files using one stream

Opening files using constructors

A constructor is used to initialize an object while it is being created.

Here a filename is used to initialize the file stream object. It involves the following steps:

Create a file stream object.

Initialize the file object with the desired fileneme.

E.g.:-

ofstream outfile(“results”);

ifstream infile(“data”);

outfile<<“total”;

outfile<<sum;

infile>>number;

We can also use the same file for both reading and writing data as shown:

Program 1

…….

…….

ofstream out(“salary”);

……..

Program 2

…….

39

Page 40: Module III

…….

ifstream in(“salary”);

……..

The connection with a file is closed automatically when the stream object expires (when the program terminates)

Instead of using two programs, we can use a single program to do both the operations on a file.

ofstream out(“salary”);

…….

out.close();

…….

ifstream in(“salary”);

……..

in.close();

Working with single file

#include<iostream.h>

#include<fstream.h>

void main()

{

char name[30];

float cost;

ofstream outf(“item”);

cout<<“enter item name”;

cin>>name;

outf<<name;

cout<<“enter item cost”

40

Page 41: Module III

cin>>cost;

outf<<cost;

outf.close();

ifstream inf(“item”);

inf>>name;

inf>>cost;

cout<<“item name”<<name;

cout<<“item cost”<<cost;

inf.close();

}

Opening files using open()

open() can be used to open multiple files that use the same stream object.

E.g.:-

ofstream outfile;

outfile.open(“DATA1”);

…….

outfile.close();

…….

outfile.open(“DATA2”);

……..

outfile.close();

#include<iostream.h>

#include<fstream.h>

void main()

41

Page 42: Module III

{

ofstream fout;

fout.open(“country”);

fout<<“USA”;

fout<<“UK”;

fout.close();

fout.open(“capital”);

fout<<“Washington”;

fout<<“London”;

fout.close();

char line[80];

ifstream fin;

fin.open(“country”);

while(fin)

{

fin.getline(line, N);

cout<<line;

}

fin.close();

fin.open(“capital”);

while(fin)

{

fin.getline(line, N);

cout<<line;

}

fin.close();

getch();}

open() : file modes

42

Page 43: Module III

The general form of open() is

stream_object.open(“filename”, mode);

The mode specifies the purpose for which the file is opened.

Mode Meaning

ios::app Append to end of file

ios::ate Go to end-of-file on opening

ios::binary Binary file

ios::in Open file for reading only

ios::out Open file for writing only

ios::nocreate Open fails if the file does not exist

ios::noreplace Open fails if the file already exist

ios::trunc Delete the contents of the file if it exists

File pointers

Each file has 2 pointers

1) get pointer or input pointer

2) put pointer or output pointer

The input pointer is used for reading the contents of a given file location.

The output pointer is used for writing to a given file location.

Each time an input or output operation occurs the appropriate pointer is automatically advanced.

When a file is opened in read-only mode the input pointer is automatically set to the beginning.

43

Page 44: Module III

When a file is opened in write-only mode the existing contents are deleted and the output pointer is set at the beginning.

When a file is opened in append mode the output pointer is set to the end-of-file.

read only H E L L O W O R

append H E L L O W O

Write only

Manipulation of File pointers

Four functions:

seekg() à moves get pointer to a specified location.

seekp() à moves put pointer to a specified location.

tellg() à gives the current position of the get pointer

tellp() à gives the current position of the put pointer

E.g.:-

infile.seekg(10);

moves the file pointer to the byte numbered 10.

ofstream outfile;

outfile.open(“hello”, ios::app);44

Page 45: Module III

int p = outfile.tellp();

value of p represents the number of bytes in the file

Seek functions can also be used with 2 arguments as follows:

seekp(offset, refposition);

seekg(offset, refposition);

the offset specifies the number of bytes the file pointer is to be moved from the refposition. The refposition can be one of the following constants.

ios::beg à start of the file

ios::cur à current position of pointer

ios::end à end of the file

Sequential i/o operations

put() and get() handle a single character at a time.

put() à writes a single character

get() à reads a single character

read() and write() handles blocks of binary data.

The general form is :

infile.read((char *) &V, sizeof(V));

outfile.write((char *) &V, sizeof(V));

The functions takes 2 arguments

1) address of the variable V

2) length of the variable in bytes.

file containing the details of n telephone customers

#include<iostream.h>

#include<fstream.h>

class telephone

{

char name[20];

char addr[40];

long telno;

45

Page 46: Module III

void getdata()

{

cout<<“enter name”;

cin>>name;

cout<<“enter addr”;

cin>>addr

cout<<“enter telno”;

cin>>telno;

}

void putdata()

{

cout<<name;

cout<<addr;

cout<<telno;

}

}

void main()

{

telephone t[50];

int n ,i;

fstream f;

f.open(“telephone.dat”, ios::in | ios::out);

cout<<“enter the no.of customers”;

cin>>n;

for(i=0; i<n; i++) {

t[i].getdata();

f.write((char *) &t[i], sizeof(t[i]));

}

46

Page 47: Module III

f.seekg(0);

for(i=0; i<n; i++)

{

f.read((char *) &t[i], sizeof(t[i]));

t[i].putdata();

} }

Random file access

Random access occur during the following situations:

modifying an existing item

adding a new item

deleting an existing item

If a file contains collection of objects of equal size then location of nth object is

int loc = n*sizeof(object);

File stock that contains the details of n items. Modify an item & display the file

#include<iostream.h>

#include<fstream.h>

class item

{

char name[20];

long code;

void getdata()

{

cout<<“enter name”;

cin>>name;

cout<<“enter code”;

cin>>code

}

47

Page 48: Module III

void putdata()

{

cout<<name;

cout<<code;

}

}

void main()

{

item t[50];

int n ,i, s ;

fstream f;

cout<<“enter the no.of tems”;

cin>>n;

f.open(“stock.dat”, ios::in | ios::out);

for(i=0; i<n; i++)

{

t[i].getdata();

f.write((char *) &t[i], sizeof(t[i]));

}

f.seekg(0);

for(i=0; i<n; i++)

{

f.read((char *) &t[i], sizeof(t[i]));

t[i].putdata();

}

cout<<“enter the item no. to be modified”;

cin>>s;

int loc = s*sizeof(t[s]);

48

Page 49: Module III

f.seekg(loc);

cout<<“enter the new details”;

t[s].getdata();

f.write((char *) &t[s], sizeof(t[s]));

f.seekg(0);

for(i=0; i<n; i++)

{

f.read((char *) &t[i], sizeof(t[i]));

t[i].putdata();

}

f.close();

getch();

}

TEMPLATES(generic classes & functions)

It is a new concept that enable us to define generic classes and functions.

Generic programming is an approach where generic types are used as parameters, so that they work for a variety of suitable data types.

Class Templates

The general format of a class template is:

template<class T>

class classname

{

……..

//class member specification with anonymous type T

}

Add 3 numbers of different data types using class template

#include<iostream.h>

template <class t1, class t2, class t3>

49

Page 50: Module III

class test

{

t1 a;

t2 b;

t3 c;

public:

void read()

{

cout<<“enter the values”;

cin>>a>>b>>c;

}

void display()

{

cout<<“a=”<<a;

cout<<“b=“<<b;

cout<<“c=“<<c;

cout<<a+b+c;

}

}

void main()

{

test<int, float, double>t;

t.read();

t.display(); getch(); }

Function Templates

Function template could be used to create a family of functions with different argument types.

The general format is:

template<class T>

50

Page 51: Module III

type function_name(arguments of type T)

{

……..

//body of the function with type T wherever appropriate

}

Swap 2 numbers using function template

#include<iostream.h>

template <class t>

void swap(t &a, t &b)

{

t temp;

temp = a;

a = b;

b= a;

}

void main()

{

int m, n;

cout<<“enter 2

cin>>m>>n;

swap(m,n);

cout<<“after swapping”;

cout<<“m=“<<m;

cout<<“n=“<<n;

float a, b;

cout<<“enter 2 floating nos”;

cin>>a>>b;

swap(a,b);

51

Page 52: Module III

cout<<“after swapping”;

cout<<“a=“<<a;

cout<<“b=“<<b;

}

Strings in MFC

MFC provides CString class for manipulating strings. It is intended to replace and extend the functionality normally provided by the C run-time library string package. The CString class supplies member functions and operators for simplified string handling, similar to those found in Basic. The class also provides constructors and operators for constructing, assigning, and comparing CStrings and standard C++ string data types.

Basic CString operations

1. CString Objects from Standard C Literal Strings

You can assign C-style literal strings to a CString just as you can assign one CString object to another:

Assign the value of a C literal string to a CString object: CString myString = "This is a test";

Assign the value of one CString to another CString object: CString oldString = "This is a test";

CString newString = oldString;

The contents of a CString object are copied when one CString object is assigned to another.

2. Accessing Individual Characters in a CString

You can access individual characters within a CString object with the GetAt and SetAt member functions. You can also use the array element, or subscript, operator ( [ ] ) instead of GetAt to get individual characters (this is similar to accessing array elements by index, as in standard C-style strings). Index values for CString characters are zero-based.

3. Concatenating Two CString Objects

To concatenate two CString objects, use the concatenation operators (+ or +=) as follows: CString s1 = "This "; //Cascading concatenation

52

Page 53: Module III

s1 += "is a "; CString s2 = "test";

CString message = s1 + "big " + s2;

//Message contains "This is a big test".

53

Page 54: Module III

At least one of the arguments to the concatenation operators (+ or +=) must be a CString object, but you can use a constant character string (such as "big") or a char (such as ‘x’) for the other argument.

4. Comparing CString Objects

The CString class overrides the relational operators (<, <=, >=, >, ==, and !=).You can compare two CStrings using these operators, as shown here:

CString s1( "Tom" ); CString s2( "Jerry" ); if( s1 < s2 )

...

5. Finding a substring

Look for a substring inside an MFC CString object. You can do this by overloading the "Find()" function to accept strings and single characters. The search takes place from left to right and returns the position of the substring.

CString s("The search capabilities of CString");

int pos = s.Find('s');

int pos2 = s.Find("of");

Representing classes and attributes using UML

The UML Class diagram provides information about the classes which includes their relationships with each other, their attributes and their operations. The UML Class diagram depicts the detailed static design of our object oriented planned software. A Class is represented with a rectangular box divided into compartments used for holding its name, its attributes and its operations.

First section for class name, second section for attributes and third section for methods.

54

Page 55: Module III

An object is an instance of a class. Depicting an object in our diagram is done by drawing an empty rectangle and writing the object name + ':' + its type and an underline. The underline will differentiate this depiction from a class description. A Class depiction doesn't include the

underline.

Car

H o n d a : Ca r

Visibility Possibilities

UML Class diagram allows using four different visibility levels:

- Private

+ Public

# Protected

~ Package

Representing Class Attributes

The attribute should be placed within the second compartment of the class (below the top compartment where we write the class title).

Representing member functions

Return types are followed by the function names. These can be omitted. The arguments may be type or name.

55

Page 56: Module III

Composition Relationships

Each instance of type Circle seems to contain an instance of type Point. This is a relationship known as composition. It can be depicted in UML using a class relationship.

The black diamond represents composition. It is placed on the Circle class because it is the Circle that is composed of a Point. The arrowhead on the other end of the relationship denotes that the relationship is navigable in only one direction. That is, Point does not know about Circle.

Inheritance

The inheritance relationship in UML is depicted by a peculiar triangular arrowhead. This arrowhead, that looks rather like a slice of pizza, points to the base class. One or more lines proceed from the base of the arrowhead connecting it to the derived classes.

56

Page 57: Module III

Italics are not always very easy to see. Therefore, as shown in Figure, an abstract class can also be marked with the {abstract} property. What’s more, though it is not a standard part of UML, I will often write Draw()=0 in the operations compartment to denote a pure virtual function.

Compile time Polymorphism:

C++ support polymorphism. One function multiple purpose, or in short many functions having same name but with different function body.For every function call compiler binds the call to one function definition at compile time. This decision of binding among several functions is taken by considering formal arguments of the function, their data type and their sequence.

Example of compile time polymorphism:

Example 1: example of compile time polymorphism; static time binding

void f(int i){cout<<"int";}

void f(char c){cout<<"char";}

int main(){   f(10);

57

Page 58: Module III

   return 0;}

Output: int

 

Run time polymorphism:

C++ allows binding to be delayed till run time. When you have a function with same name, equal number of arguments and same data type in same sequence in base class as well derived class and a function call of form: base_class_type_ptr->member_function(args); will always call base class member function. The keyword virtual on a member function in base class indicates to the compiler to delay the binding till run time.

Every class with atleast one virtual function has a vtable that helps in binding at run time. Looking at the content of base class type pointer it will correctly call the member function of one of possible derived / base class member function.

Example of run time polymorphism:

class Base{public:

    virtual void display(int i)    { cout<<"Base::"<<i; }};

class Derv: public Base{public:

    void display(int j)    { cout<<"Derv::"<<j; }};

int main(){    Base *ptr=new Derv;

58

Page 59: Module III

    ptr->display(10);    return 0;} 

Output: Derv::10

Hybrid Inheritance in c++

Hybrid inheritance is combination of two or more inheritances such as single,multiple,multilevel or Hierarchical inheritances. In the given figure class B inherits property(member function) of class A which is base class and class D inherits property from class B and class C.#include<iostream.h>#include<conio.h> class A     //Base class{public:int l;void len(){cout<<"\n\nLenght :::\t";   cin>>l;                  //Lenght is enter by user       }};class B :public A   //Inherits property of class A {public:int b,c;void l_into_b()   {len();cout<<"\n\nBreadth :::\t";cin>>b;                      //Breadth is enter by user

59

Page 60: Module III

c=b*l;                       //c stores value of lenght * Breadth i.e. (l*b) .   }}; class C{public:int h;void height(){cout<<"\n\nHeight :::\t";cin>>h;                  //Height is enter by user }}; //Hybrid Inheritance Levelclass D:public B,public C{public:int res;void result(){l_into_b();height();res=h*c;                          //res stores value of c*h  where c=l*b and h is height which is enter by user cout<<"\n\nResult (l*b*h) :::\t"<<res;}}; int main(){clrscr();D d1;d1.result();getch();

}The mechanism of deriving a new class from more than one form for inheritance is called

hybrid inheritance.  In some situations we need to apply 2 or more types of inheritances in the design of our program. For example consider the following hierarchy of classes.      

1)    It’s a combination of single-level, multi-level, multiple and hybrid Ineritance. 2)    Here the resultant (last or grand-child) Child class in the structure can acquire duplicate copies from the grand parent class. 3)    In situations where the resultant child class can acquire duplicate copies of the grand parent class then grand parent class used during inheritance is accompanied with “ virtual “ keyword, to avoid duplicity in the grand child class

60

Page 61: Module III

Why a friend function cannot be used to overload the assignment operator=

The assignment operator is explicitly required to be a class member operator. That is a sufficient reason for the compiler to fail to compile your code. Assignment is one of the special member functions defined in the standard (like the copy constructor) that will be generated by the compiler if you do not provide your own.

Unlike other operations that can be understood as external to the left hand side operator, the assignment is an operation that is semantically bound to the left hand side: modify this instance to beequal to the right hand side instance (by some definition of equal), so it makes sense to have it as an operation of the class and not an external operation. On the other hand, other operators as addition are not bound to a particular instance: is a+b an operation of a or b or none of them? -- a and b are used in the operation, but the operation acts on the result value that is returned.That approach is actually recommended and used: define operator+= (that applies to the instance) as a member function, and then implement operator+ as a free function that operates on the result:struct example { example& operator+=( const example& rhs );};example operator+( const example& lhs, const example& rhs ) { example ret( lhs ); ret += rhs; return ret;}// usually implemented as:// example operator+( example lhs, const example& rhs ) {// return lhs += rhs; // note that lhs is actually a copy, not the real lhs//}

Program to perform complex number arithmetic operations using operator overloading

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

class complex{float real,img;

public:complex(){

61

Page 62: Module III

real=0;img=0;}complex(float a,float b){real=a;img=b;}

void get(){cout<<”\n\nEnter the real part of number: “;cin>>real;cout<<”\n\nEnter the imaginary part of number: “;cin>>img;}

void print(){cout<<”(“<<real<<”)”<<” + “<<”(“<<img<<”i”<<”)”;}

complex operator+(complex c1){complex temp;temp.real=real+c1.real;temp.img=img+c1.img;return temp;}

complex operator-(complex c1){complex temp;temp.real=real-c1.real;temp.img=img-c1.img;return temp;}

complex operator*(complex c1){complex temp;temp.real=(real*c1.real)-(img*c1.img);temp.img=(img*c1.real)+(real*c1.img);

62

Page 63: Module III

return temp;}

complex operator/(complex c1){

complex temp,c2;c2.img=-c1.img;float x;temp.real=(real*c1.real)-(img*(c2.img));temp.img=(real*c1.real)+(real*(c2.img));x=(c1.real)*(c1.real)+(c1.img)*(c1.img);temp.real=temp.real/x;temp.img=temp.img/x;return temp;}

};

void main(){complex c1,c2,c3;int choice;char ans;clrscr();do{cout<<”\n\n MENU: “;cout<<”\n\n\t1.Addition\n\n\t2.Subtraction\n\n\t3.Multiplication\n\n\t4.Division”;cout<<”\n\nEnter your choice: “;cin>>choice;switch(choice){case 1:c1.get();c2.get();c3=c1+c2;cout<<”\n\nAddition is: “;c3.print();break;

case 2:c1.get();

63

Page 64: Module III

c2.get();c3=c1-c2;cout<<”\n\nSubtraction is: “;c3.print();break;

case 3:c1.get();c2.get();c3=c1*c2;cout<<”\n\nMultiplication is: “;c3.print();break;

case 4:c1.get();c2.get();c3=c1/c2;cout<<”\n\nDivision is: “;c3.print();break;

}cout<<”\n\nDo you want to continue?(y/n): “;fflush(stdin);cin>>ans;}while(ans==’y’ || ans==’Y');getch();

}

Program to overload ‘+’ operator for concatenating two strings.

#include<conio.h>

#include<string.h>

#include<iostream.h>

64

Page 65: Module III

class string {

public:

char *s;

int size;

void getstring(char *str)

{

size = strlen(str);

s = new char[size];

strcpy(s,str);

}

void operator+(string);

};

void string::operator+(string ob)

{

size = size+ob.size;

s = new char[size];

strcat(s,ob.s);

65

Page 66: Module III

cout<<"\nConcatnated String is: "<<s;

}

void main()

{

string ob1, ob2;

char *string1, *string2;

clrscr();

cout<<"\nEnter First String:";

cin>>string1;

ob1.getstring(string1);

cout<<"\nEnter Second String:";

cin>>string2;

ob2.getstring(string2);

66

Page 67: Module III

//Calling + operator to Join/Concatenate strings

ob1+ob2;

getch();

}

Microsoft Foundation Class

The MFCs are a set of predefined classes. These classes provide an object-oriented approach to windows programming that encapsulates the windows API. All the classes in MFC have names beginning with C

CDocument CView

Data members of an MFC class are prefixed with m_.

Document- the collection of data.

A document is not limited to text. It could be the data for a game etc..

View- how the data is to be displayed in a window, and how the user can interact with it

A document object can have as many view objects associated with it as you want.

Document Interfaces:

SDI: Single Document Interface

Your application only open one document at a time.

MDI: Multiple Document Interface

Multiple documents can be opened in your application. Each document is displayed in a child window of the application window.

Linking a document and its views:

MFC incorporates a mechanism for integrating-

67

Page 68: Module III

A document with its views-A document object automatically maintains a list of pointers to its associated views. A view object has a pointer to the document.

A frame window with a view- A frame window has a pointer to the currently active view object.

Document templates:

A document template object creates document objects and frame window objects. View of an object is created by a frame window object. The application object creates the document template object.

Document Template Classes:

MFC has two classes for defining document templates.

68

Page 69: Module III

CSingleDocTemplate for SDI CMultiDocTemplate for MDI

Document/View classes:

Document class is derived from the CDocument class in the MFC library.

You will add your own data members to store items that your application requires and member function to support processing of that data.

Your view class is derived from the CView class

The application class:

The class CWinApp is fundamental to any windows program written using MFC. An object of this class includes everything necessary for starting, initializing, running and

closing the application.

class CMyApp: public CWinApp{public:virtual BOOL InitInstance();

};The window class:

The CFrameWnd class provides everything for creating and managing a window for your application.

All you need to add to the derived window class is a constructor.

Class CMyWnd : public CFrameWnd{Public:// constructorCMyWnd()

{Create(0,L”Our Dump MFC Application”);}

};

69

Page 70: Module III

Some characteristics of MFC

1. Convenience of reusable code:

– Many tasks common to all Windows apps are provided by MFC– Our programs can inherit and modify this functionality as needed– We don't need to recreate these tasks– MFC handles many clerical details in Windows programs

2. Produce smaller executables:

– Typically 1/3 the size of their API counterparts

3. Can lead to faster program development:

– But there's a steep learning curve--– Especially for newcomers to object –oriented programming

4. MFC Programs must be written in C++ and require the use of classes

– Programmer must have good grasp of:• How classes are declared, implemented (instantiated), extended, overridden, and used• Encapsulation• Inheritance• Polymorphism

Define a class template stack with push and pop operations. Create stack objects with integer and real data items.

#include<iostream.h>#include<conio.h>#include<stdlib.h>#define MAX 50template<class T>class STACK{ T stack[MAX]; static int top;

public: void push(); void pop(); void display();};

70

Page 71: Module III

template<class T>int STACK<T>::top=-1;

template<class T>void STACK <T>::push(){ int item; if(top==(MAX-1)) { cout<<endl<<"Stack is overflow:"; getch(); exit(0); } else { cout<<endl<<"Enter the element which you want to insert:"; cin>>item; if(top==-1) { top=0; } stack[top]=item; }}template<class T>void STACK <T>::pop(){ int item; if(top==-1) { cout<<endl<<"stack is in underflow condition:"; getch(); exit(0); } else { item=stack[top]; cout<<endl<<"Deleted element from the stack is:"<<item; top=top-1; }

71

Page 72: Module III

}}template<class T>void STACK <T>::display(){ int i; for(i=top;i>=0;i--) { cout<<stack[i]; }}int main(){

STACK <int> s1; int ch; clrscr(); cout<<endl<<"1.Push Operation:"; cout<<endl<<"2.Pop Operation:"; cout<<endl<<"3.Display Operation:"; cout<<endl<<"4.exit"; do { cout<<endl<<"Enter your choice:"; cin>>ch; switch(ch) { case 1: s1.push(); break; case 2: s1.pop(); break; case 3: s1.display(); break; case 4: exit(0); break; default: cout<<endl<<"Your choice is wrong:";

72

Page 73: Module III

} } while(ch>=1&&ch<=4); getch(); return(0);}

Define classes Geometric Shape, Rectangle, Square and Circle, with proper relationship between them, to compute their area.

#include <iostream.h>using namespace std;

class GeometricShape { protected: int d1, d2; public: void set_values (int a, int b) { d1=a; d2=b; } };

class Rectangle: public GeometricShape { public: int area () { return (d1* d2); } };

class Square: public GeometricShape { public: int area () { return (d1*d1); } };

class Circle: public GeometricShape { public: int area () { return (3.14*d1*d1/2); } };

int main () { Rectangle rect; Square sq; Circle c;

73

Page 74: Module III

GeometricShape * ppoly1 = &rect; ppoly1->set_values (4,5); cout << ppoly1.area() << endl; ppoly1 = &sq; cout << ppoly1.area() << endl; ppoly1 = &c; cout << ppoly1.area() << endl;

return 0;}

Overriding member function

We can define data member and member function with the same name in both base and derived

class. When the function with same name exists in both class and derived class, the function in

the derived class will get executed. This means, the derived class will get executed. This means,

the derived class function overrides the base class function.

E.g.

Class base A

{

Public:

Void getdata ()

{

————-

————–

}

74

Page 75: Module III

};

Class derived B: public base A

{

Public:

Void getdata ()

{

—————-

—————-

}

};

Void main ()

{

Derived B obj;

Obj. getdata ();

getdata ();

}

 

75

Page 76: Module III

When the statement obj. getdata (); get executed, the function getdata () of the derived class i.e.

of derived B get executed. This means, the derived class function overrides the base class

function.

The scope resolution (:: ) operator can be used to access base class function through an object of

the derived class.

E.g.

Derived B obj;

Obj. Base A:: getdata ();

The above statements specify that the getdata () of base A is to be called.

A base class function can be accessed from within the derived class by as follows also:

Class derived B: public base A

{

Public:

Void getdata ()

{

Base A:: getdata ();   // call getdata () of base A

}

};

76

Page 77: Module III

Overriding Member Functions

When you define a base class, you must consider whether derived classes will need to override any of your base-class member functions. For each member function in the base class, there are three possibilities:

The base-class function is suitable for all derived classes. Derived classes will never need to override the member function with customized behavior. The Credit and Debit member functions in BankAccount fit this scenario. These functions simply add or subtract money from the balance— derived classes do not need to override these member functions. Here’s an example:

__gc __abstract class BankAccount{public: void Credit(double amount); // This function cannot be // overridden void Debit(double amount); // Neither can this one ...};

The base-class function performs some task, but derived classes might need to override the function to provide customized behavior. To enable a base-class function to be overridden, you must declare the function using the virtual keyword in the base-class definition, as shown in this example:

__gc __abstract class BankAccount{public: virtual String * ToString(); // This function can be // overridden ...};

The base-class function specifies some operation that is required by all derived classes, but each derived class needs to perform the operation in a significantly different way. There is no sensible common behavior you can define in the base class. To achieve this effect, declare the base-class member function using the virtual keyword. At the end of the function prototype, use the syntax = 0, as shown in the following code. This syntax indicates that the function isn’t implemented in the base class—derived classes must override this function. Here’s an example:

__gc __abstract class BankAccount{public: virtual bool CanDebit(double amount) = 0; // This

77

Page 78: Module III

// function // must be // overridden ...

};

78