48
Overriding This phenomena is used in situations where there is inheritance relationship between classes. Explanation: In the previous example, the derived class DERIVED, has a function fn(), which it has inherited from the base class BASE. The derived class can modify the definition of the function fn() which it gets from its base class. This process where the base class function is modified by the derived class, is called overriding. The derived class might either add new content, retain the same content or enhance the existing content within the function.

Multiple Inheritance

Embed Size (px)

DESCRIPTION

C ++

Citation preview

Overriding • This phenomena is used in situations where

there is inheritance relationship between classes.

Explanation:

• In the previous example, the derived class DERIVED, has a function fn(), which it has inherited from the base class BASE.

• The derived class can modify the definition of the function fn() which it gets from its base class.

• This process where the base class function is modified

by the derived class, is called overriding.

• The derived class might either add new content, retain the same content or enhance the existing content within the function.

Access Specifiers….revisited…

• The access specifiers of a class are:

private

protected

public

Private

• The private members of a class can be

accessed only by the member functions of

that class.

• private keyword and a “:” symbol are used

to indicate the section of the code, which is

to be treated as private.

private:

Protected

• The protected members of a class can be accessed only by the member functions of that class, and the member functions of the classes derived from it.

• protected keyword and “:” symbol are used to indicate the section of the code, that is to treated as protected.

protected:

Public

• The public members of a class can be

accessed anywhere in the application.

• public keyword and “:” symbol are used to

indicate the section of the code, that is to

treated as public.

• public:

Power of access….

• An object defined outside a class can only access the public members of the class.

• The private members of a class cannot be directly accessed from outside the class.

• For example, the object of the class DERIVED, named d1, cannot directly access the private member variable, c.

• Hence the following code, raises error.

DERIVED d1;

d1.c=34;

Contd…

• This holds true even of the class that is derived from another class.

• Even though the derived class inherits all the data and methods from the base class, the private members of the base class are not accessible within the derived class.

• The idea here is not to compromise on encapsulation implemented through data hiding.

Contd….

• If the derived class, could access the private

members of the base class, then the strong

wall of encapsulation created by data hiding

could be easily broken by creating a dummy

derived class.

• That would defeat the whole purpose of data

hiding and security.

Using Protected Access Specifier…Putting

forward a realistic problem

• Consider the following problem:

• The class “Encryption”, has a private

member function called keycompare().

• A class, called cryptfile, is derived from the

class, Encryption.

• The following code shows the partial

declarations……..

Example…. class Encryption

{

private: void keycompare()

{

……

}

public:

…….

};

class cryptfile : public Encryption

{

……….

};

int main()

{

………..

}

Explanation….

• The function, keycompare(), is meant for

internal use by the class, Encryption.

• The derived class, cryptfile, may need to call the

function, keycompare().

• As this function is private, it is not accessible outside the class, Encryption.

• This function, however, if made public, would be

accessible throughout the program, which is

not what the designer intended.

Contd….

• The protected access specifier is used to solve the above-mentioned problem.

• A protected member of a class can be accessed by its member functions or within any class derived from it.

• Protected members behave like public members with respect to the derived class and like private members with respect to the rest of the program.

Contd…. • A class may contain all, private, protected and public access

specifiers.

• A programmer can decide……… which members require to be

declared using which access specifier, and label accordingly.

• Example: class Ex

{

private:

int a;

void fn1();

protected:

int b;

void fn2();

public:

int c;

void fn3();

};

Access Specifiers of Derivation

• class BASE

{

};

class DERIVED : _______ BASE

{

};

While inheriting, from the base class, an access

specifier should be specified, in the blank.

Contd…

• The access specifier can be private, protected or

public.

• Thus, access restrictions get imposed when

deriving the class.

Using Access Specifiers during

Derivation…

• The public Access Specifier:

In a public access specifier, all the private

members of a base class remain private in the

object, the protected members remain protected,

and the public members remain public.

Contd….

• The protected Access Specifier:

In a protected access specifier, all the private members of a base class remain private in the object, the protected members remain

protected, but all the public members of the base class become protected.

• Programmers rarely use this form of inheritance.

Contd….

• The privateAccess Specifier:

In a private access specifier, all the private members of a base class remain private in the object and all the public and protected

members in the base class become private.

• This form of inheritance depicts a composition relationship between base and the derived classes.

Illustrating 3 types of Inheritance derivations…. Note

the use of different access specifier in each derivation in

each case.

• Case I class BASE

{

private:

int a,b;

protected:

int c,d;

public:

int e;

int fn();

};

class DERIVED : public BASE

{

private:

int p,q;

protected:

int r, s;

public:

int t;

int D( );

};

• Case 2 class BASE

{

private:

int a,b;

protected:

int c,d;

public:

int e;

int fn();

};

class DERIVED: protected BASE

{

private:

int p,q;

protected:

int r, s;

public:

int t;

int D( );

};

• Case 3 class BASE

{

private:

int a,b;

protected:

int c,d;

public:

int e;

int fn();

};

class DERIVED: private BASE

{

private:

int p,q;

protected:

int r, s;

public:

int t;

int D( );

};

Shown below is the visual representation of the

objects of the DERIVED class….

• One object is shown for each case, and the access specifiers

of the members of the objects are also shown alongside.

a b p q

c d r s

e fn() t D( )

a b p q

c d e r s fn()

t D( )

a b c d p q

e fn()

r s

t D( )

Private Members

Protected Members Public Members

Case 1 Case 2 Case 3

Let’s understand…

• In the code shown previously, e is a public

member variable of the BASE class.

• As it can be seen from the visual representation of the object, the member variable, e, has public access in the object, if DERIVED has a public access specifier.

• It has a protected access in the object, if DERIVED has a protected access specifier.

• It has a private access in the object, if DERIVED has a private access specifier.

Contd…

• In the DERIVED object of the type, CASE 1 (public access specifier), the vafunction fn().riable, a could have been accessed through the

• In CASE 3, the function itself has gone into the private area of the object and thus, the variables of the BASE class can no longer be accessed.

• Thus public inheritance (through public access specifier in derivation) propagates hierarchy, while a private inheritance (through private access specifier in derivation) effectively stops a hierarchy.

The Golden rule of Access Specifiers

• ONCE PRIVATE ALWAYS PRIVATE.

• A public member can be made protected or

private, a protected member can be made private,

but ONCE PRIVATE ALWAYS PRIVATE.

• Any non-private variable or method made private

either by original declaration or private

inheritance will remain private on all further

inheritances.

Order of call of Constructors &

Destructors…

• Constructors are called in the order of BASE-to-DERIVED.

• Destructors are called in the order of DERIVED-to-BASE.

Example for order of invoking of constructors and destructors • #include< iostream.h>

#include<iomanip.h>

class BASE

{

public:

BASE()

{

cout<<“Constructor of BASE”<<endl;

}

~BASE()

{

cout<<“Destructor of BASE”<< endl;

}

};

Contd…

class DERIVED : public BASE

{

public:

DERIVED()

{

cout<<“Constructor of DERIVED”<<endl;

}

~DERIVED()

{

cout<<“Destructor of DERIVED”<<endl;

}

};

int main()

{

DERIVED obj;

return 0;

}

Output of the program is…..

• Constructor of BASE

• Constructor of DERIVED

• Destructor of DERIVED

• Destructor of BASE

Uses of Inheritance

• Extending Functionality:

It is quite possible that in a large project, several programmers share a class.

In such case, individual programmers may not be permitted to modify the class.

If a programmer wants to add certain functions or attributes to the class at this stage, he or she may create a new class that inherits all the members from the original class and then, use the derived class.

This brings about reusability, rather than recreation from scratch.

Another use of Inheritance…

• Implementation of Generalization:

Generalization is the building up of a hierarchy by

grouping the common attributes and methods of

several classes into one base class and inheriting the members in various derived classes.

B1 B2

B3 B4

B5

Derived1

Further derived classes

Types of Inheritance…

• One important object-oriented mechanism is multiple inheritance.

• Multiple inheritance means that one subclass can have more than one superclass.

• This enables the subclass to inherit properties of more than one superclass and to ``merge'' their properties.

• If class A inherits from more than one class, ie. A inherits from B1, B2, ..., Bn, it is called as multiple inheritance.

• A Familiar example of MI is children inheriting different characteristics of their parents.

Syntax of MI

• class A: public base1, public base2

{

//body of class

};

Example… • #include< iostream.h>

class base1

{

protected:

int ivar1;

public:

void show1 ()

{

cout<<ivar1<<endl;

}

};

class base2

{

protected:

int ivar2;

public:

void show2()

{

cout<<ivar2<<endl; } };

Contd….

• class derived : public base1, public base2

{

public:

void set(int ix, int iy)

{

ivar1=ix;

ivar2=iy;

}

};

int main()

{

derived obj;

obj.set(10,20)

obj.show1();

obj.show2(); return 0;

}

Access Specifier in MI…

• The default access specifier is private.

• class derived : public base1, base2

{

};

This means that, base1 will have public access and base2 would have private, since it has not been mentioned.

If one intends public access, one should explicitly declare.

Ambiguity in Multiple Inheritance…

• Multiple Inheritance creates a lot of ambiguities.

• For example, what happens when two base

classes contain a function of the same

name?

• The program below illustrates this

ambiguity, as the function disp() is inherited

from both the classes, base1 and base2.

Example of Ambiguity in MI…

• #include<iostream.h>

class base1

{

public:

void disp()

{

cout<<“Base1”<<endl;

}

};

class base2

{

public:

void disp()

{

cout<<“Base2”<<endl;

}

};

Contd….

class derived : public base1, public base2

{

};

int main()

{

derived obj;

obj.disp(); //ambiguous function call

return 0;

}

Ambiguity…

• In main() function of the above program, the

reference to the function, disp() is ambiguous.

• The compiler does’nt know which function to

invoke, that of the class, base1, or the class base2,

since the derived class does not have the disp()

function.

• The ambiguity can be resolved in few ways.

• One of the way is use of scope resolution operator

while calling the function.

Rewriting the main() of the above

program to resolve ambiguity…

• int main()

{

derived obj;

obj.base1::disp(); //calling disp() of base1

obj.base2::disp(); //calling disp() of base2

return 0;

}

2nd method to resolve ambiguity… Using Overriding…….

#include<iostream.h>

class base1

{

public:

void disp()

{

cout<<“Base1”<<endl;

}

};

class base2

{

public:

void disp()

{

cout<<“Base2”<<endl;

}

};

The program… • #include<iostream.h>

class A

{

public:

int Avar;

};

class B : public A

{

public:

int Bvar;

};

class C: public A

{

public:

int Cvar;

};

Contd… class D: public B, public C

{

public :

int Dvar;

};

int main()

{

D Dtemp;

Dtemp.Avar=10; //This is ambiguous

return 0;

}

Contd…

The above program will display an error

because the reference to the variable Avar

in Dtemp is ambiguous.

This ambiguity is caused because class D

inherits one copy of Avar through class

B and another through class C

Resolving the ambiguity….

• This ambiguity can be resolved in 2 ways.

• The first method is to use the scope resolution

operator :: • Let’s modify the main() in the following manner:

• int main()

{

D Dtemp;

Dtemp.B::Avar=10; // Refers to Avar inherited from class B

Dtemp.C::Avar=20; // Refers to Avar inherited from class C

return 0;

}

The other way is to use a Virtual Base class

• The principle behind virtual base classes is to have

only one copy of the base class members in

memory.

• Inheriting a class more than once through multiple

paths creates multiple copies of the base class

members in memory.

• Thus, by declaring the base class inheritance as

virtual, only one copy of the base class is inherited.

• A base class inheritance can be specified as

virtual using the virtual qualifier.

Example……

• class A

{…….};

class B : virtual public A

{……};

class C: virtual public A

{……};

class D: virtual public C

{……};

Contd….

int main()

{

D Dtemp;

Dtemp.Avar=10; //No ambiguity because only one

return 0; // copy of Avar exists.

}

The virtual qualifier

• In the above example, the classes, B and C,

use the virtual keyword to inherit the

members of class A.

• Thus, class A is the virtual base class and

class D inherits only one copy of the

member data, Avar, from class A.

• Therefore, any reference to the member,

Avar, through an object of class C does not

lead to ambiguity.