0% found this document useful (0 votes)
3 views33 pages

Hierarchical Classifications. Characteristics Common: Inheritance

Inheritance allows for the creation of hierarchical classifications where a base class defines common characteristics that can be inherited by derived classes. Access control for base class members can be public, private, or protected, affecting how derived classes can access these members. Constructors and destructors are executed in a specific order, with base class constructors running before derived class constructors and destructors running in reverse order.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views33 pages

Hierarchical Classifications. Characteristics Common: Inheritance

Inheritance allows for the creation of hierarchical classifications where a base class defines common characteristics that can be inherited by derived classes. Access control for base class members can be public, private, or protected, affecting how derived classes can access these members. Constructors and destructors are executed in a specific order, with base class constructors running before derived class constructors and destructors running in reverse order.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 33

Inheritance

Inheritance allows creation of hierarchical classifications.

Using inheritance, a general class can be created that defines


characteristics common to a set of related classes. This class may then
be inherited by other, more specific classes, each adding only those
things that are unique to the inheriting class.

A class that is inherited is referred to as a base class. The class that does
the inheriting is called the derived class.

Further, a derived class can be used as a base class for another derived
class. In this way, multiple inheritance is achieved.
Base-Class Access Control
When a derived class inherits the members of the base class, the base class
members become the members of the derived class.
Class inheritance uses this general form:
class derived-class-name : access base-class-name
{
// body of class
};
The access status of the base-class members inside the derived class is determined
by access.The base-class access specifier must be either public, private, or
protected.
If no access specifier is present, the access specifier is private by default if the
derived class is a class. If the derived class is a struct, then public is the default in
the absence of an explicit access specifier.
public inheritance:

When the access specifier for a base class is public, all public members
of the base become public members of the derived class, and all
protected members of the base become protected members of the
derived class. In all cases, the base's private elements remain private
to the base and are not accessible by members of the derived class
# include <iostream>
using namespace std;
class A { int main()
int i, j; {
public: B ob(3);
void set (int a, int b) { i=a; j=b; } ob.set(1, 2); // access member of base
void show() ob.show(); // access member of base
{ cout << i << " " << j << "\n"; } ob.showk(); // uses member of derived
}; class
class B : public A { return 0;
int k; }
public:
B(int x) { k=x; }
void showk()
{ cout << k << "\n"; }
};
private inheritance:
When the base class is inherited by using the private access specifier,
all public and protected members of the base class become private
members of the derived class.
For example, the following program will not even compile because
both set( ) and show( ) are now private elements of derived:

When a base class' access specifier is private, public and protected


members of the base become private members of the derived class.
This means that they are still accessible by members of the derived class
but cannot be accessed by parts of the program that are not members of
either the base or derived class.
# include <iostream>
using namespace std;
class A { int main()
int i, j; {
public: B ob(3);
void set(int a, int b) { i=a; j=b; } ob.set(1, 2); //cannot access
void show() { cout << i << " " << j << "\n"; } ob.show(); // cannot access
}; ob.showk();
return 0;
class B: private A }
{
int k;
public:
B(int x) { k=x; }
void showk() { cout << k << "\n"; }
};
Inheritance and protected Members
When a member of a class is declared as protected, that member is not accessible
by other parts of the program. Access to a protected member is the same as access
to a private member—it can be accessed only by other members of its class.

If the base class is inherited as public, then the base class' protected members
become protected members of the derived class and are, therefore, accessible by
the derived class. By using protected access specifier, class members can be
created that are private to their class but that can still be inherited and accessed by
a derived class.
#include <iostream>
using namespace std;
class A {
protected:
int i, j; // private to base, but accessible by derived
public:
void set(int a, int b) { i=a; j=b; } int main() {
void show() { cout << i << " " << j << "\n"; } B ob;
}; ob.set(2, 3); // accessible in derived
class
class B : public A {
ob.show(); //accessible in derived class
int k;
ob.setk();
public:
ob.showk();
// derived may access base's i and j
return 0; }
void setk() { k=i*j; }
void showk() { cout << k << "\n"; }
};
In this example, because base is inherited by derived as public and because i and j
are declared as protected, derived function setk( ) may access them. If i and j had
been declared as private by base, then derived would not have access to them, and
the program would not compile.

When a derived class is used as a base class for another derived class, any
protected member of the initial base class that is inherited (as public) by the first
derived class may also be inherited as protected again by a second derived class.
#include <iostream>
// i and j inherited indirectly through
using namespace std;
derived1.
class A {
class B2 : public B1 {
protected:
int m;
int i, j;
public:
public:
void setm()
void set(int a, int b) { i=a; j=b; }
{ m = i - j;
void show() { cout << i << " " << j << "\n"; }
} // legal
};
// i and j inherited as protected.
void showm()
class B1 : public A {
{
int k;
cout << m << "\n";
public:
}
void setk() { k = i*j; } // legal
void showk() { cout << k << "\n"; }
};
};
int main()
If, however, base were inherited as private, then all members
{
of base would become private members of derived1, which
B1 ob1;
means that they would not be accessible by derived2.
ob1.set(2, 3);
(However,i and j would still be accessible by derived1.)
ob1.show();
ob1.setk();
ob1.showk();
B2 ob2;
ob2.set(3, 4);
ob2.show();
ob2.setk();
ob2.showk();
ob2.setm();
ob2.showm();
return 0;
}
// This program won't compile. int main()
#include <iostream> {
using namespace std; B1 ob1;
class A { ob1.set(1, 2); //error, can't use set()
protected: int i, j; ob1.show(); //error, can't use show()
public: return 0;
void set(int a, int b) { i=a; j=b; } }
void show() { cout << i << " " << j << "\n"; }
};
// Now, all elements of base are private in B1.
class B1 : private base {
int k;
public:
// this is legal because i and j are private to B1
void setk() { k = i*j; } // can be invoked
void showk() { cout << k << "\n"; } // can be invoked
Protected Base-Class Inheritance
Base class members can be inherited using protected access specifier. When
inherited, all public and protected members of the base class become protected
members of the derived class.
#include <iostream>
using namespace std;
class A {
protected:
int i, j; // private to base, but accessible by derived
public:
void setij(int a, int b)
{ i=a; j=b; }
void showij()
{ cout << i << " " << j << "\n"; }
};
// Inherit base as protected. int main()
class B : protected A{ {
int k; B ob;
public: // ob.setij(2, 3); // setij() is protected
// derived may access base's i and j and setij(). member of derived
void setk() ob.setk(); // Can be invoked, public
{ member of derived
setij(10, 12); ob.showall(); // Can be invoked, public
k = i*j; member of derived
} // ob.showij(); // showij() is protected
// may access showij() here member of derived
void showall() return 0;
{ cout << k << " "; }
showij(); }
};
Inheriting Multiple Base Classes
A derived class can inherit two or more base classes.
Ex:#include <iostream> // Inherit multiple base classes.
using namespace std; class derived: public base1, public base2
class base1 {
{ public:
protected: void set(int i, int j)
int x; { x=i; y=j;
public: }
void showx() { cout << x << "\n"; } };
}; int main()
class base2 { {
protected: derived ob;
int y; ob.set(10, 20); // provided by derived
public: ob.showx(); // from base1
void showy() {cout << y << "\n";} ob.showy(); // from base2
}; return 0;
}
#include<iostream> class C : public A,public B
using namespace std; {
class A public:
{ void display()
protected: {
int a; cout<<"Addition of a and b is : "<<a+b;
public: cout<<"Subtraction of a and b is : "<<a-b;
void get_a(int n) cout<<"Multiplication of a and b is : "<<a*b;
{ cout<<"Division of a and b is : "<<a\b;
a=n; }
} };
};
class B
{
int main()
protected: {
int b; C c;
public: c.get_a(10);
void get_b(int n) c.get_b(20);
{
b=n;
c.display();
} return 0;
}; }
Constructors, Destructors, and Inheritance
When Constructor and Destructor Functions Are Executed Base and derived classes can have
their constructor and destructor function. Base class constructors are executed before executing
derived class constructors. Derived class destructors will be executed first before executing
base class destructors.
#include <iostream>
using namespace std; int main()
class base { {
public: derived ob;
base() { cout << "Constructing base\n"; } return 0;
~base() { cout << "Destructing base\n"; } }
};
class derived: public base {
public:
Constructing base
derived() { cout << "Constructing derived\n"; }
Constructing derived
~derived() { cout << "Destructing derived\n"; }
Destructing derived
};
Destructing base
The program constructs and then destroys an object called ob that is of class derived.
When an object of a derived class is created, if the base class contains a constructor, it will be
called first, followed by the derived class' constructor.

When a derived object is destroyed, its destructor is called first, followed by the base class‘
destructor, if it exists.

Constructor functions are executed in their order of derivation.


Destructor functions are executed in reverse order of derivation.
include <iostream>
int main()
using namespace std;
{
class base {
derived2 ob;
public:
// construct and destruct ob
base() { cout << "Constructing base\n"; }
return 0;
~base() { cout << "Destructing base\n"; }
}
};
class derived1 : public base {
public:
derived1() { cout << "Constructing derived1\n"; }
~derived1() { cout << "Destructing derived1\n"; }
};
Constructing base
Constructing derived1
class derived2: public derived1 {
Constructing derived2
public:
Destructing derived2
derived2() { cout << "Constructing derived2\n"; }
Destructing derived1
~derived2() { cout << "Destructing derived2\n"; }
Destructing base
};
The same general rule applies in situations involving multiple base classes.
#include <iostream> class derived: public base1, public base2 {
using namespace std; public:
class base1 { derived()
public: { cout << "Constructing derived\n"; }
base1() { cout << "Constructing base1\n"; } ~derived()
~base1() { cout << "Destructing base1\n"; } { cout << "Destructing derived\n"; }
}; };

class base2 { int main()


public: {
base2() { cout << "Constructing base2\n"; } derived ob;
~base2() { cout << "Destructing base2\n"; } // construct and destruct ob
}; return 0; Constructing base1
} Constructing base2
Constructing derived
Destructing derived
Destructing base2
Destructing base1
As you can see, 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. This means that had base2 been specified
before base1 in derived's list, as shown here:

class derived: public base2, public base1 {

then the output of this program would have looked like this:
Constructing base2
Constructing base1
Constructing derived
Destructing derived
Destructing base1
Destructing base2
Passing Parameters to Base-Class Constructors
If a base class contains parameterized constructor, it can be called explicitly from derived
class constructor.
derived-constructor(arg-list) : base1(arg-list),
base2(arg-list),

baseN(arg-list)
{
// body of derived constructor
}
Here, base1 through baseN are the names of the base classes inherited by the derived class.
Colon separates the derived class' constructor definition from the base-class specifications,
and that the base-class specifications are separated from each other by commas, in case of
multiple base classes.
Ex:#include <iostream> ~derived()
using namespace std; { cout << "Destructing derived\n"; }
class base { void show()
protected: { cout << i << " " << j << "\n"; }
int i; };
public:
base(int x)
{ i=x; cout << "Constructing base\n"; }
~base() { cout << "Destructing base\n"; }
}; int main() {
class derived: public base { derived ob(3, 4);
int j; ob.show(); // displays 4 3
public: return 0;
// derived uses x; y is passed along to base. }
derived(int x, int y): base(y)
{ j=x;
cout << "Constructing derived\n";
}
Multiple base class : Parameterized constructor - explicit invocation
#include <iostream> class derived: public base1, public base2 {
using namespace std; int j;
class base1 { public:
protected: derived(int x, int y, int z): base1(y), base2(z)
int i; { j=x;
public: cout << "Constructing derived\n";
base1(int x) }
{ i=x; cout << "Constructing base1\n"; } ~derived()
~base1() { cout << "Destructing base1\n"; } { cout << "Destructing derived\n"; }
}; void show() { cout << i << " " << j << " " << k << "\
class base2 { n"; }

protected: };
int k; int main()
public: {
base2(int x) { k=x; cout << "Constructing base2\n"; } derived ob(3, 4, 5);
~base2() { cout << "Destructing base1\n"; } ob.show(); // displays 4 3 5
}; return 0; }
Granting Access
When a base class is inherited as private, all public and protected members of that class
become private members of the derived class. However, in certain circumstances, it might be
necessary to restore one or more inherited members to their original access specification.
Ex: it might be necessary to grant certain public members of the base class public status in
the derived class even though the base class is inherited as private.
In Standard C++, there are two ways to accomplish this.
1. By coding “using” statement
2. By using an “access declaration” within the derived class. (deprecated)

General form: base-class::member;

The access declaration is put under the appropriate access heading in the derived class.
class base {
public:
int j; // public in base
};
// Inherit base as private.
class derived: private base {
public:
// here is access declaration
base::j; // make j public again
..
};
Because base is inherited as private by derived, the public member j is made a private member of
derived. However, by including
base::j;
as the access declaration under derived public heading, j is restored to its public status.
Access declaration can be used to restore the access rights of public and protected members.
However, access declaration cannot be used to raise or lower a member's access status.
Ex: a member declared as private in a base class cannot be made public by a derived class.
Program generates warning, because access-declaration syntax is deprecated.
#include <iostream> int main()
using namespace std; {
class base { derived ob;
int i; // private to base //ob.i = 10; // because i is private in derived
public:
int j, k;
ob.j = 20; // legal because j is made public in derived
void seti(int x) { i = x; } //ob.k = 30; // because k is private in derived
int geti() { return i; } ob.a = 40; // legal because a is public in derived
}; ob.seti(10);
class derived: private base { cout << ob.geti() << " " << ob.j << " " << ob.a;
public: return 0;
/* The next three statements override base's }
inheritance as private and restore j, seti(), and geti() to public access. */
base::j; // make j public again - but not k
base::seti; // make seti() public
base::geti; // make geti() public
// base::i; // illegal, cannot elevate access
int a; // public
};
Ex: Program uses ‘using’ keyword to change the access specifier of the inherited member.
No, deprecation warnings will be generated.
#include <iostream>
int main()
using namespace std;
{
class base {
derived ob;
int i; // private to base
//ob.i = 10; // because i is private in derived
public:
ob.j = 20; // legal because j is made public in
int j, k;
derived
void seti(int x) { i = x; }
//ob.k = 30; // because k is private in derived
int geti() { return i; }
ob.a = 40; // legal because a is public in derived
};
class derived: private base { ob.seti(10);
public: cout << ob.geti() << " " << ob.j << " " << ob.a;
using base::j; // make j public again - but not k return 0; }
using base::seti; // make seti() public
using base::geti; // make geti() public
Access declarations are supported in C++ to accommodate
// base::i; // illegal, cannot elevate access those situations in which most of an inherited class is intended
int a; // public to be made private, but a few members are to retain their
}; publicor protected status.
Virtual Base Classes
An element of ambiguity can be introduced into a C++ program when multiple base classes are
inherited // This program contains an error and will not compile.
#include <iostream>
using namespace std; int main() {
class base { derived3 ob;
public: int i; ob.i = 10; // this is ambiguous, which i???
}; ob.j = 20;
class derived1 : public base { ob.k = 30;
public: int j; // i ambiguous here, too
}; ob.sum = ob.i + ob.j + ob.k;
class derived2 : public base { // also ambiguous, which i?
public: int k; cout << ob.i << " ";
}; cout << ob.j << " " << ob.k << " ";
class derived3 : public derived1, public cout << ob.sum;
derived2 { return 0; }
public: int sum;
Both derived1 and derived2 inherit base. However, derived3 inherits both derived1 and
derived2. This means that there are two copies of base present in an object of type derived3.
An expression like ob.i = 10; induces ambiguity There are two copies of base present in object ob,
one from dervied1 and the other from derived2.
There are two ways to remove ambiguity.
1. To use scope resolution operator to i and manually select one i.
2. To use virtual keyword while inheriting from base to derived1 and derived2.

Ex: Program to resolve ambiguity using scope resolution operator


// This program uses explicit scope resolution to select i.
#include <iostream> class derived2 : public base
using namespace std; { public: int k;
class base };
{ public: int i;
};
class derived1 : public base
{ public: int j;
};
/* derived3 inherits both derived1 and derived2. This means that there are two copies of
base in derived3! */
class derived3 : public derived1, public derived2
{ public: int sum;
};
int main( )
{
derived3 ob;
ob.derived1::i = 10; // scope resolved, use derived1's i
ob.j = 20;
ob.k = 30;
ob.sum = ob.derived1::i + ob.j + ob.k;
cout << "derived1::i value "<<ob.derived1::i <<endl;
cout << "derived2::i value "<<ob.derived2::i <<endl;
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
The use of :: has manually selected derived1's version of base.
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:
// This program uses virtual base classes. // derived2 inherits base as virtual.
#include <iostream> class derived2 : virtual public base {
using namespace std; public:
class base { int k;
public: };
int i; };
/* derived3 inherits both derived1 and derived2.
// derived1 inherits base as virtual.
This time, there is only one copy of base class. */
class derived1 : virtual public base {
class derived3 : public derived1, public derived2 {
public:
public:
int j;
int sum};
};
int main()
One further point to keep in mind: Even though both
{
derived1 and derived2 specify base as virtual, base is
derived3 ob;
still present in objects of either type.
ob.i = 10; // now unambiguous
For example, the following sequence is perfectly valid:
ob.j = 20;
// define a class of type derived1
ob.k = 30;
derived1 myclass;
// unambiguous
myclass.i = 88;
ob.sum = ob.i + ob.j + ob.k;
// unambiguous
The only difference between a normal base class and a
cout << ob.i << " ";
virtual one is what occurs when an object inherits the
cout << ob.j << " " << ob.k << " ";
base more than once.
cout << ob.sum;
return 0;
If virtual base classes are used, then only one base class
}
is present in the object. Otherwise, multiple copies will
be found.

You might also like