PPT8
PPT8
1
Content
• Constructor and Destructor in Inheritance
• Inheritance and Static Functions
• Virtual class
• Abstract Class
• Pure Virtual Functions
Constructors and Destructors in Base and
Derived Classes
• Derived classes can have their own constructors and destructors.
• When an object of a derived class is created, the base class’s
constructor is executed first, followed by the derived class’s
constructor.
• When an object of a derived class is destroyed, its destructor is called
first, then that of the base class.
3
//EXAMPLE ~derived()
#include<iostream> { cout << "Destructing derived\n"; }
Using namespace std; };
//base class int main()
class base { {
public: derived ob;
base() // do nothing but construct and
{ cout << "Constructing base\n"; } destruct ob
return 0;
~base()
{ cout << "Destructing base\n"; } }
};
//derived class
class derived: public base { Program Output
public: Constructing base
Constructing derived
derived()
Destructing derived
{ Destructing base
cout << "Constructing derived\n"; }
4
Constructors and Destructors with Multiple Base
Classes
• Constructors are called in order of derivation, left to right, as
specified in derived's inheritance list.
• Destructors are called in reverse order, right to left.
5
//MULTI-LEVEL class derived2: public derived1 {
#include <iostream> public:
using namespace std; derived2() { cout <<
class base { "Constructing derived2\n"; }
public: ~derived2() { cout <<
"Destructing derived2\n"; }
base() };
{ cout << "Constructing base\n"; int main()
}
~base() { cout << "Destructing {
base\n"; } derived2 ob;
}; // construct and destruct ob
class derived1 : public base { return 0;
public: } Program Output:
derived1() { cout << Constructing base
"Constructing derived1\n"; } Constructing derived1
~derived1() { cout << Constructing derived2
"Destructing derived1\n"; } Destructing derived2
}; Destructing derived1
Destructing base
6
//MULTIPLE BASE CASES class derived: public base1, public
#include <iostream> base2 {
using namespace std; public:
class base1 { derived() { cout << "Constructing
derived\n"; }
public: ~derived() { cout << "Destructing
base1() { cout << "Constructing derived\n"; }
base1\n"; } };
~base1() { cout << "Destructing int main()
base1\n"; }
}; {
class base2 { derived ob;
public: // construct and destruct ob
base2() { cout << "Constructing return 0;
base2\n"; } } Program Output:
Constructing base1
~base2() { cout << "Destructing Constructing base2
base2\n"; } Constructing derived
}; Destructing derived
Destructing base2
Destructing base1
7
Passing Arguments to Base Class Constructor
derived-constructor(arg-list) : base1(arg-list),
base2(arg-list),
// ...
baseN(arg-list)
{
// body of derived constructor
}
8
Order of Constructor Call
• Base class constructors are always called in the derived class
constructors.
• Whenever you create derived class object, first the base class default
constructor is executed and then the derived class's constructor
finishes execution.
9
//EXAMPLE // derived uses x; y is passed
#include <iostream> along to base.
using namespace std; derived(int x, int y): base(y)
class base { { j=x;
protected: cout << "Constructing
derived\n"; }
int i; ~derived() { cout << "Destructing
public: derived\n"; }
base(int x) void show() { cout << i << " " << j
<< "\n"; }
{ i=x; cout << "Constructing
base\n"; } };
~base() { cout << "Destructing int main()
base\n"; } {
}; derived ob(3, 4);
class derived: public base { ob.show(); // displays 4 3
int j; return 0;
public: }
10
//MULTIPLE BASE CASES class derived: public base1, public
#include <iostream> base2 {
int j;
using namespace std;
class base1 { public:
12
Here’s what actually happens when derived is instantiated:
• Memory for derived is set aside (enough for both the Base and
Derived portions)
• The appropriate Derived constructor is called
• The Base object is constructed first using the appropriate Base
constructor. If no base constructor is specified, the default
constructor will be used.
• The initialization list initializes variables
• The body of the constructor executes
• Control is returned to the caller
13
Points to note
• It is important to understand that arguments to a base-class
constructor are passed via arguments to the derived class' constructor.
• Even if a derived class‘ constructor does not use any arguments, it will
still need to declare one if the base class requires it.
• In this situation, the arguments passed to the derived class are simply
passed along to the base.
14
Why is Base class Constructor called inside Derived class?
• Constructors have a special job of initializing the object properly.
• A Derived class constructor has access only to its own class members,
but a Derived class object also have inherited property of Base class,
and only base class constructor can properly initialize base class
members.
• Hence all the constructors are called, else object wouldn't be
constructed properly.
15
// This program contains an int main() {
error and will not compile. derived3 ob;
#include <iostream> ob.i = 10; // this is
ambiguous, which i???
using namespace std;
ob.j = 20;
class base {
ob.k = 30;
public: int i; }; // i ambiguous here, too
class derived1 : public base { ob.sum = ob.i + ob.j + ob.k;
public: int j; }; // also ambiguous, which i?
class derived2 : public base { cout << ob.i << " ";
public: int k; }; cout << ob.j << " " << ob.k ;
class derived3 : public
cout << ob.sum;
derived1, public derived2 { return 0;
public: int sum; }; }
16
Discussion
• which ‘i’ is being referred to, the one in derived1 or the one in
derived2?
• Because there are two copies of base present in object ob, there are
two ob.is! ->, the statement is inherently ambiguous.
• There are two ways to remedy the preceding program.
• The first is to apply the scope resolution operator to i and manually
select one i. Example (on next slide).
17
// This program uses explicit int main()
scope resolution to select i. {
#include <iostream>
derived3 ob;
using namespace std;
ob.derived1::i = 10; // scope
class base { public: int i; }; resolved, use derived1's i
// derived1 inherits base. ob.j = 20;
class derived1 : public base { ob.k = 30;
public: int j; }; // scope resolved
// derived2 inherits base. ob.sum = ob.derived1::i + ob.j +
class derived2 : public base { ob.k;
public: int k; }; // also resolved here
class derived3 : public cout << ob.derived1::i << " ";
derived1, public derived2 { cout << ob.j << " " << ob.k << " ";
public: int sum; }; cout << ob.sum;
return 0; }
18
Discussion
• As you can see, because the :: was applied, the program has
manually selected derived1's version of base.
• What if only one copy of base is actually required? Is there some way
to prevent two copies from being included in derived3?
• This solution is achieved using virtual base classes.
20
• When two or more objects are derived from a common base class, you
can prevent multiple copies of the base class from being present in an
object derived from those objects by declaring the base class as virtual
when it is inherited.
• You accomplish this by preceding the base class' name with the
keyword virtual when it is inherited.
• For example, here is another version of the example program in which
derived3 contains only one copy of base:
21
// This program uses virtual base classes. int main()
#include <iostream>
using namespace std;
{
class base { public: int i; }; derived3 ob;
ob.i = 10; // now unambiguous
// derived1 inherits base as virtual.
ob.j = 20;
class derived1 : virtual public base { ob.k = 30;
public: int j; }; // unambiguous
// derived2 inherits base as virtual. ob.sum = ob.i + ob.j + ob.k;
// unambiguous
class derived2 : virtual public base { cout << ob.i << " ";
public: int k; };
cout << ob.j << " " << ob.k << " ";
class derived3 : public derived1, public cout << ob.sum;
derived2
{ public: int sum; }; return 0;
}
22
Discussion
• As you can see, the keyword virtual precedes the rest of the inherited
class‘specification.
• Now that both derived1 and derived2 have inherited base as virtual,
any multiple inheritance involving them will cause only one copy of
base to be present.
• Therefore, in derived3, there is only one copy of base and ob.i = 10 is
perfectly valid and unambiguous.
23
Inheritance and Static Functions
24
Virtual base class
• They are used to prevent the confusion or duplicity among child
classes during inheritance.
• Consider the following situation:
class A {
public: void show() {cout<<"In A"<<endl;}
};
int main(){
Dog obj; obj.sound(); obj.sleeping();
}
Output:
Woof
Sleeping
class Animal{
public:
virtual void sound() = 0;
void sleeping() {cout<<"Sleeping"; }
};
class Dog: public Animal{
public:
void sound() {cout<<"Woof"<<endl;}
};
int main(){
Animal *obj = new Dog;
obj->sound();
}
Output:
Woof
Abstract Class
• An abstract class is designed to act as base class. It is a design concept
in program development and provides a base upon which other
classes may be built.
• Abstract Class is a class which contains atleast one Pure Virtual
function in it. Abstract classes are used to provide an Interface for its
sub classes. Classes inheriting an Abstract Class must provide
definition to the pure virtual function, otherwise they will also
become abstract class.
34
Characteristics of Abstract Class
• Abstract class cannot be instantiated, but pointers and references of
Abstract class type can be created.
• Abstract class can have normal functions and variables along with a
pure virtual function.
• Classes inheriting an Abstract Class must implement all pure virtual
functions, or else they will become Abstract too.
35
Pure Virtual Functions
• Pure virtual Functions are virtual functions with no definition.
• They start with virtual keyword and ends with = 0.
• Syntax for a pure virtual function,
virtual void fun() = 0;
36
//Abstract base class int main()
class Base { {
public: //Base obj; (Compile Time
virtual void show() = 0; }; Error)
class Derived:public Base { Base *b;
public: Derived d;
void show() b = &d;
{ b->show();
cout << "Implementation of return 0;
Virtual Function in Derived }
class";
}
};
37
Note:
• Pure Virtual functions can be given a small definition in the Abstract
class, which you want all the derived classes to have. Still you cannot
create object of Abstract class.
• Also, the Pure Virtual function must be defined outside the class
definition. If you will define it inside the class definition, complier will
give an error. Inline pure virtual definition is Illegal.
38
Polymorphism
Contents
• Polymorphism
• Function Overloading
• Default Function Arguments
• Ambiguity in Function Overloading
Polymorphism
• The word polymorphism means having many
forms. In simple words, we can define
polymorphism as the ability of a message to
be displayed in more than one form.
{
return i*j;
}
Key Points
• The key point about function overloading is that the functions must differ in regard to the types
and/or number of parameters. Two functions differing only in their return types cannot be
overloaded.
• For example, this is an invalid attempt to overload myfunc( ):
int myfunc(int i);
float myfunc(int i);
// Error: differing return types are insufficient when overloading.
• Sometimes, two function declarations will appear to differ, when in
fact they do not. For example, consider the following declarations.
void f(int *p);
void f(int p[]); // error, *p is same as p[]
• Remember, to the compiler *p is the same as p[ ]. Therefore, although the two prototypes appear
to differ in the types of their parameter, in actuality they do not.
Example 3
Example 4
(Function overloading in classes)
Inheritance based Polymorphism
Example
Extend the Logic
Virtual Functions
• Be aware that the virtual function mechanism works only with
pointers to objects and, with references, not with objects themselves.
Class Activity (15 minutes)
• Can you showcase polymorphism (Drive function in various types
of automobiles) in context of VEHICLES ?
Overloading vs overriding
• Function overloading – same function name but
different arguments. Functions are defined in the
same class.
Also known as early or static binding Also known as late or dynamic binding
It executes faster because the function It executes slower because the function
is resolved at compilation time only. is resolved at Run-time.
int main()
{
cout << myfunc(10.1) << " "; // unambiguous, calls
myfunc(double)
cout << myfunc(10); // ambiguous
return 0;
}
Thanks