Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Unit 3 - Oops

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

Unit 3

C++ Inheritance
In C++, inheritance is a process in which one object acquires all the properties and behaviors of its
parent object automatically. In such way, you can reuse, extend or modify the attributes and
behaviors which are defined in other class.

In C++, the class which inherits the members of another class is called derived class and the class
whose members are inherited is called base class. The derived class is the specialized class for the
base class.

Advantage of C++ Inheritance


Code reusability: Now you can reuse the members of your parent class. So, there is no need to
define the member again. So less code is required in the class.

Polymorphism in Java | Dynamic Method Dispatch

Types Of Inheritance
C++ supports five types of inheritance:

o Single inheritance
o Multiple inheritance
o Hierarchical inheritance
o Multilevel inheritance
o Hybrid inheritance

1 NOTES BY A V MAHALLE
Derived Classes
A Derived class is defined as the class derived from the base class.

The Syntax of Derived class:

class derived_class_name :: visibility-mode base_class_name


{
// body of the derived class.
}

derived_class_name: It is the name of the derived class.

visibility mode: The visibility mode specifies whether the features of the base class are publicly
inherited or privately inherited. It can be public or private.

base_class_name: It is the name of the base class.

o When the base class is privately inherited by the derived class, public members of the base class
becomes the private members of the derived class. Therefore, the public members of the base class
are not accessible by the objects of the derived class only by the member functions of the derived
class.
o When the base class is publicly inherited by the derived class, public members of the base class also
become the public members of the derived class. Therefore, the public members of the base class are
accessible by the objects of the derived class as well as by the member functions of the base class.

Note:
o In C++, the default mode of visibility is private.
o The private members of the base class are never inherited.

C++ Single Inheritance


Single inheritance is defined as the inheritance in which a derived class is inherited from the only
one base class.

2 NOTES BY A V MAHALLE
Where 'A' is the base class, and 'B' is the derived class.

C++ Single Level Inheritance Example: Inheriting Fields


When one class inherits another class, it is known as single level inheritance. Let's see the example
of single level inheritance which inherits the fields only.

1. #include <iostream>
2. using namespace std;
3. class Account {
4. public:
5. float salary = 60000;
6. };
7. class Programmer: public Account {
8. public:
9. float bonus = 5000;
10. };
11. int main(void) {
12. Programmer p1;
13. cout<<"Salary: "<<p1.salary<<endl;
14. cout<<"Bonus: "<<p1.bonus<<endl;
15. return 0;
16. }

Output:

Salary: 60000
Bonus: 5000

In the above example, Employee is the base class and Programmer is the derived class.

C++ Single Level Inheritance Example: Inheriting Methods


Let's see another example of inheritance in C++ which inherits methods only.
3 NOTES BY A V MAHALLE
1. #include <iostream>
2. using namespace std;
3. class Animal {
4. public:
5. void eat() {
6. cout<<"Eating..."<<endl;
7. }
8. };
9. class Dog: public Animal
10. {
11. public:
12. void bark(){
13. cout<<"Barking...";
14. }
15. };
16. int main(void) {
17. Dog d1;
18. d1.eat();
19. d1.bark();
20. return 0;
21. }

Output:

Eating...
Barking...

Let's see a simple example.

1. #include <iostream>
2. using namespace std;
3. class A
4. {
5. int a = 4;
6. int b = 5;
7. public:
8. int mul()
9. {
10. int c = a*b;
11. return c;
12. }

4 NOTES BY A V MAHALLE
13. };
14.
15. class B : private A
16. {
17. public:
18. void display()
19. {
20. int result = mul();
21. std::cout <<"Multiplication of a and b is : "<<result<< std::endl;
22. }
23. };
24. int main()
25. {
26. B b;
27. b.display();
28.
29. return 0;
30. }

Output:

Multiplication of a and b is : 20

In the above example, class A is privately inherited. Therefore, the mul() function of class 'A' cannot
be accessed by the object of class B. It can only be accessed by the member function of class B.

How to make a Private Member Inheritable


The private member is not inheritable. If we modify the visibility mode by making it public, but this
takes away the advantage of data hiding.

C++ introduces a third visibility modifier, i.e., protected. The member which is declared as protected
will be accessible to all the member functions within the class as well as the class immediately derived
from it.
Visibility modes can be classified into three categories:

5 NOTES BY A V MAHALLE
o Public: When the member is declared as public, it is accessible to all the functions of the program.
o Private: When the member is declared as private, it is accessible within the class only.
o Protected: When the member is declared as protected, it is accessible within its own class as well as
the class immediately derived from it.

Visibility of Inherited Members


Base class visibility Derived class visibility

Public Private Protected

Private Not Inherited Not Inherited Not Inherited

Protected Protected Private Protected

Public Public Private Protected

C++ Multilevel Inheritance


Multilevel inheritance is a process of deriving a class from another derived class.

C++ Multi Level Inheritance Example


When one class inherits another class which is further inherited by another class, it is known as multi
level inheritance in C++. Inheritance is transitive so the last derived class acquires all the members
of all its base classes.

Let's see the example of multi level inheritance in C++.

1. #include <iostream>
2. using namespace std;
3. class Animal {
4. public:
6 NOTES BY A V MAHALLE
5. void eat() {
6. cout<<"Eating..."<<endl;
7. }
8. };
9. class Dog: public Animal
10. {
11. public:
12. void bark(){
13. cout<<"Barking..."<<endl;
14. }
15. };
16. class BabyDog: public Dog
17. {
18. public:
19. void weep() {
20. cout<<"Weeping...";
21. }
22. };
23. int main(void) {
24. BabyDog d1;
25. d1.eat();
26. d1.bark();
27. d1.weep();
28. return 0;
29. }

Output:

Eating...
Barking...
Weeping...

C++ Multiple Inheritance


Multiple inheritance is the process of deriving a new class that inherits the attributes from two or
more classes.

7 NOTES BY A V MAHALLE
Syntax of the Derived class:

1. class D : visibility B-1, visibility B-2, ?


2. {
3. // Body of the class;
4. }

Let's see a simple example of multiple inheritance.

1. #include <iostream>
2. using namespace std;
3. class A
4. {
5. protected:
6. int a;
7. public:
8. void get_a(int n)
9. {
10. a = n;
11. }
12. };
13.
14. class B
15. {
16. protected:
17. int b;
18. public:
19. void get_b(int n)
20. {
21. b = n;
22. }
23. };
24. class C : public A,public B
25. {
26. public:
27. void display()
28. {
29. std::cout << "The value of a is : " <<a<< std::endl;
30. std::cout << "The value of b is : " <<b<< std::endl;
31. cout<<"Addition of a and b is : "<<a+b;

8 NOTES BY A V MAHALLE
32. }
33. };
34. int main()
35. {
36. C c;
37. c.get_a(10);
38. c.get_b(20);
39. c.display();
40.
41. return 0;
42. }

Output:

The value of a is : 10
The value of b is : 20
Addition of a and b is : 30

In the above example, class 'C' inherits two base classes 'A' and 'B' in a public mode.

Ambiquity Resolution in Inheritance


Ambiguity can be occurred in using the multiple inheritance when a function with the same name
occurs in more than one base class.

Let's understand this through an example:

1. #include <iostream>
2. using namespace std;
3. class A
4. {
5. public:
6. void display()
7. {
8. std::cout << "Class A" << std::endl;
9. }
10. };
11. class B
12. {
13. public:
14. void display()

9 NOTES BY A V MAHALLE
15. {
16. std::cout << "Class B" << std::endl;
17. }
18. };
19. class C : public A, public B
20. {
21. void view()
22. {
23. display();
24. }
25. };
26. int main()
27. {
28. C c;
29. c.display();
30. return 0;
31. }

Output:

error: reference to 'display' is ambiguous


display();

o The above issue can be resolved by using the class resolution operator with the function. In the above
example, the derived class code can be rewritten as:

1. class C : public A, public B


2. {
3. void view()
4. {
5. A :: display(); // Calling the display() function of class A.
6. B :: display(); // Calling the display() function of class B.
7.
8. }
9. };

An ambiguity can also occur in single inheritance.

Consider the following situation:

1. class A
2. {
3. public:
10 NOTES BY A V MAHALLE
4. void display()
5. {
6. cout<<?Class A?;
7. }
8. } ;
9. class B
10. {
11. public:
12. void display()
13. {
14. cout<<?Class B?;
15. }
16. } ;

In the above case, the function of the derived class overrides the method of the base class. Therefore,
call to the display() function will simply call the function defined in the derived class. If we want to
invoke the base class function, we can use the class resolution operator.

1. int main()
2. {
3. B b;
4. b.display(); // Calling the display() function of B class.
5. b.B :: display(); // Calling the display() function defined in B class.
6. }

C++ Hybrid Inheritance


Hybrid inheritance is a combination of more than one type of inheritance.

11 NOTES BY A V MAHALLE
Let's see a simple example:

1. #include <iostream>
2. using namespace std;
3. class A
4. {
5. protected:
6. int a;
7. public:
8. void get_a()
9. {
10. std::cout << "Enter the value of 'a' : " << std::endl;
11. cin>>a;
12. }
13. };
14.
15. class B : public A
16. {
17. protected:
18. int b;
19. public:
20. void get_b()
21. {
22. std::cout << "Enter the value of 'b' : " << std::endl;
23. cin>>b;
24. }
25. };
26. class C
27. {
28. protected:
29. int c;
30. public:
31. void get_c()
32. {
33. std::cout << "Enter the value of c is : " << std::endl;
34. cin>>c;
35. }
36. };
37.
38. class D : public B, public C
12 NOTES BY A V MAHALLE
39. {
40. protected:
41. int d;
42. public:
43. void mul()
44. {
45. get_a();
46. get_b();
47. get_c();
48. std::cout << "Multiplication of a,b,c is : " <<a*b*c<< std::endl;
49. }
50. };
51. int main()
52. {
53. D d;
54. d.mul();
55. return 0;
56. }

Output:

Enter the value of 'a' :


10
Enter the value of 'b' :
20
Enter the value of c is :
30
Multiplication of a,b,c is : 6000

C++ Hierarchical Inheritance


Hierarchical inheritance is defined as the process of deriving more than one class from a base class.

Syntax of Hierarchical inheritance:

1. class A
2. {
13 NOTES BY A V MAHALLE
3. // body of the class A.
4. }
5. class B : public A
6. {
7. // body of class B.
8. }
9. class C : public A
10. {
11. // body of class C.
12. }
13. class D : public A
14. {
15. // body of class D.
16. }

Let's see a simple example:

1. #include <iostream>
2. using namespace std;
3. class Shape // Declaration of base class.
4. {
5. public:
6. int a;
7. int b;
8. void get_data(int n,int m)
9. {
10. a= n;
11. b = m;
12. }
13. };
14. class Rectangle : public Shape // inheriting Shape class
15. {
16. public:
17. int rect_area()
18. {
19. int result = a*b;
20. return result;
21. }
22. };
23. class Triangle : public Shape // inheriting Shape class
14 NOTES BY A V MAHALLE
24. {
25. public:
26. int triangle_area()
27. {
28. float result = 0.5*a*b;
29. return result;
30. }
31. };
32. int main()
33. {
34. Rectangle r;
35. Triangle t;
36. int length,breadth,base,height;
37. std::cout << "Enter the length and breadth of a rectangle: " << std::endl;
38. cin>>length>>breadth;
39. r.get_data(length,breadth);
40. int m = r.rect_area();
41. std::cout << "Area of the rectangle is : " <<m<< std::endl;
42. std::cout << "Enter the base and height of the triangle: " << std::endl;
43. cin>>base>>height;
44. t.get_data(base,height);
45. float n = t.triangle_area();
46. std::cout <<"Area of the triangle is : " << n<<std::endl;
47. return 0;
48. }

Output:

Enter the length and breadth of a rectangle:


23
20
Area of the rectangle is : 460
Enter the base and height of the triangle:
2
5
Area of the triangle is : 5

15 NOTES BY A V MAHALLE
constructors and destructors in derived classes in cpp
In C++, constructors and destructors are special member functions that are used to initialize and clean up
objects of a class, respectively. When dealing with derived classes (also known as subclasses), which inherit
properties and behavior from a base class (also known as a superclass), constructors and destructors
behave in a specific way.
Let's break down constructors and destructors in the context of derived classes:
1. Constructors in Derived Classes:
When you create an object of a derived class, its constructor is responsible for initializing both the
derived class's attributes and the inherited attributes from the base class. This involves invoking
the base class's constructor before initializing the specific attributes of the derived class. This can
be achieved using an initializer list in the derived class's constructor.

class Base
{
public:
Base(int val)
{ /* constructor logic */ }
};

class Derived : public Base


{
public:
Derived(int val1, int val2) : Base(val1)
{ // Initialize Derived-specific attributes }
};

2. Destructors in Derived Classes: When an object of a derived class goes out of scope or is explicitly
deleted, its destructor is called. Similar to constructors, destructors follow an order from derived
class to base class. First, the derived class's destructor is executed, followed by the base class's
destructor. This ensures that any resources acquired in the derived class are released properly
before moving up the inheritance chain.

class Base
{
public:
~Base()
{ /* destructor logic */ }
};
16 NOTES BY A V MAHALLE
class Derived : public Base
{
public:
~Derived()
{ // Cleanup Derived-specific resources }
};

To summarize, constructors in derived classes handle initialization of both the derived and base class
members, while destructors in derived classes handle cleanup in reverse order, ensuring that resources are
released properly.

Example:

#include <iostream>

class Animal {
protected:
std::string mName;

public:
Animal(const std::string& name) : mName(name) {
std::cout << "Animal constructor: " << mName << std::endl;
}

~Animal() {
std::cout << "Animal destructor: " << mName << std::endl;
}

};

class Dog : public Animal {


protected:
std::string mBreed;

public:
Dog(const std::string& name, const std::string& breed) : Animal(name), mBreed(breed) {
std::cout << "Dog constructor: " << mName << ", Breed: " << mBreed << std::endl;
}

~Dog() {
std::cout << "Dog destructor: " << mName << ", Breed: " << mBreed << std::endl;
}

};

int main() {

17 NOTES BY A V MAHALLE
Dog myDog("Buddy", "Golden Retriever");
return 0;
}

Output:
Animal constructor: Buddy
Dog constructor: Buddy, Breed: Golden Retriever
Dog destructor: Buddy, Breed: Golden Retriever
Animal destructor: Buddy

Explanation:

class Animal {
public:
Animal(const std::string& name) : mName(name) {
std::cout << "Animal constructor: " << mName << std::endl;
}

Here, we define a class Animal with a constructor that takes a name parameter and initializes the private
member mName with the provided value. Inside the constructor, a message is printed indicating that the
Animal constructor is being called, along with the name of the animal.

&: The ampersand (&) symbol in const std::string& denotes that name is a reference to a std::string. In
C++, when you pass an argument by reference, you are essentially passing a reference to the original
object rather than making a copy of it. This can be more efficient than passing objects by value,
especially for large objects like strings.

class Dog : public Animal {


public:
Dog(const std::string& name, const std::string& breed) : Animal(name), mBreed(breed) {
std::cout << "Dog constructor: " << mName << ", Breed: " << mBreed << std::endl;
}

Here, we define a derived class Dog that publicly inherits from the Animal base class. The derived class
has a constructor Dog(const std::string& name, const std::string& breed) which takes both a name and a
breed parameter. This constructor first calls the Animal constructor to initialize the base class part of
the Dog object. Then, it initializes the protected member mBreed with the provided breed value. It prints
a message indicating that the Dog constructor is being called, along with the name and breed of the dog.

Pointers and references to derived types:-


Polymorphism is also accomplished using pointers in C++. It allows a pointer in a base class
to point to either a base class object or to any derived class object. We can have the
following Program segment show how we can assign a pointer to point to the object of the
derived class.

18 NOTES BY A V MAHALLE
class base
{
//Data Members
//Member Functions
};
class derived : public base
{
//Data Members
//Member functions
};
void main ( )
{
base *ptr; //pointer to class base derived obj ;
ptr = &obj ;//indirect reference obj to the pointer
//Other Program statements
}
Example:
#include <iostream>#include <iostream>

// Base class
class Base {
public:
void Show() {
std::cout << "Common function in the base class" << std::endl;
}
};

// Derived class
class Derived : public Base {
public:
void Display() {
std::cout << "Derived class function" << std::endl;
}
};

int main() {
Base b;
Derived d;

Base* bPtr = &b;


Derived* dPtr = &d;
19 NOTES BY A V MAHALLE
// Access members of the base class using the base pointer
bPtr->Show();

// Access members of the derived class using the derived pointer


dPtr->Show();
dPtr->Display();

return 0;
}

Output:
Common function in the base class
Common function in the base class
Derived class function

Pointers can be declared to derived class.It can be used to access members of base class
and derived class. A base class pointer can also be used to point to object of derived class
but it can access only members that are inherited from base class.

C++ virtual function


A C++ virtual function is a member function in the base class that you redefine in a derived class. It is
declared using the virtual keyword.
It is used to tell the compiler to perform dynamic linkage or late binding on the function.
There is a necessity to use the single pointer to refer to all the objects of the different classes. So, we
create the pointer to the base class that refers to all the derived objects. But, when base class pointer
contains the address of the derived class object, always executes the base class function. This issue can
only be resolved by using the 'virtual' function.
A 'virtual' is a keyword preceding the normal declaration of a function.
When the function is made virtual, C++ determines which function is to be invoked at the runtime based
on the type of the object pointed by the base class pointer.
Late binding or Dynamic linkage
In late binding function call is resolved during runtime. Therefore compiler determines the type of object at
runtime, and then binds the function call.

Rules of Virtual Function:


1. Virtual functions must be members of some class.
2. Virtual functions cannot be static members.
3. They are accessed through object pointers.

20 NOTES BY A V MAHALLE
4. They can be a friend of another class.
5. A virtual function must be defined in the base class, even though it is not used.
6. The prototypes of a virtual function of the base class and all the derived classes must be identical. If
the two functions with the same name but different prototypes, C++ will consider them as the
overloaded functions.
7. We cannot have a virtual constructor, but we can have a virtual destructor
Consider the situation when we don't use the virtual keyword.

#include <iostream>
using namespace std;
class A
{
int x=5;
public:
void display()
{
std::cout << "Value of x is : " << x<<std::endl;
}
};
class B: public A
{
int y = 10;
public:
void display()
{
std::cout << "Value of y is : " <<y<< std::endl;
}
};
int main()
{
A *a;
B b;
a = &b;
a->display();
return 0;
}
Output:

Value of x is : 5

In the above example, * a is the base class pointer. The pointer can only access the base class members but
not the members of the derived class. Although C++ permits the base pointer to point to any object
derived from the base class, it cannot directly access the members of the derived class. Therefore, there is
a need for virtual function which allows the base pointer to access the members of the derived class.

C++ virtual function Example

21 NOTES BY A V MAHALLE
Let's see the simple example of C++ virtual function used to invoked the derived class in a program.

#include <iostream>
{
public:
virtual void display()
{
cout << "Base class is invoked"<<endl;
}
};
class B:public A
{
public:
void display()
{
cout << "Derived Class is invoked"<<endl;
}
};
int main()
{
A* a; //pointer of base class
B b; //object of derived class
a = &b;
a->display(); //Late Binding occurs
}
Output:

Derived Class is invoked

Pure Virtual Function:


A virtual function is not used for performing any task. It only serves as a placeholder.
When the function has no definition, such function is known as "do-nothing" function.
The "do-nothing" function is known as a pure virtual function. A pure virtual function is a function declared
in the base class that has no definition relative to the base class.
A class containing the pure virtual function cannot be used to declare the objects of its own, such classes
are known as abstract base classes.
The main objective of the base class is to provide the traits to the derived classes and to create the base
pointer used for achieving the runtime polymorphism.
Pure virtual function can be defined as:
virtual void display() = 0;
Let's see a simple example:

22 NOTES BY A V MAHALLE
#include <iostream>
using namespace std;
class Base
{
public:
virtual void show() = 0;
};
class Derived : public Base
{
public:
void show()
{
std::cout << "Derived class is derived from the base class." << std::endl;
}
};
int main()
{
Base *bptr;
//Base b;
Derived d;
bptr = &d;
bptr->show();
return 0;
}
Output:
Derived class is derived from the base class.

In the above example, the base class contains the pure virtual function. Therefore, the base class is an
abstract base class. We cannot create the object of the base class.

Pure virtual functions and abstract types in cpp


In C++, pure virtual functions and abstract types are key concepts in object-oriented programming and are
used to achieve abstraction and polymorphism. They are fundamental for implementing interfaces and
creating base classes that cannot be instantiated directly. Let's explore these concepts:

Pure Virtual Functions:


A pure virtual function is a function declared in a C++ class that has no implementation in the base class
and is marked with the virtual keyword followed by "= 0". It serves as a placeholder for a function that
must be implemented in derived classes. The presence of a pure virtual function makes a class abstract,
which means you cannot create instances (objects) of it.
Example:

class Shape {
public:
23 NOTES BY A V MAHALLE
virtual void area() const = 0; // Pure virtual function
};

class Circle : public Shape {


private:
double radius;

public:
Circle(double r) : radius(r) {}

void area() const override {


double a = 3.14159 * radius * radius;
std::cout << "Area of Circle: " << a << std::endl;
}
};

In this example, the Shape class is abstract due to the pure virtual function area(). The Circle class is a
concrete class that derives from Shape and provides an implementation for the pure virtual function.

Abstract Types:
An abstract type is a class that contains one or more pure virtual functions, making it impossible to create
instances of that class directly. Abstract types are used as base classes for creating derived classes with
specific implementations. They are often used to define interfaces or common behaviors for a group of
related classes.

Example:
class Animal {
public:
virtual void speak() const = 0; // Pure virtual function
};

class Dog : public Animal {


public:
void speak() const override {
std::cout << "Woof! Woof!" << std::endl;
}
};

class Cat : public Animal {


public:
void speak() const override {
std::cout << "Meow!" << std::endl;
}
};

24 NOTES BY A V MAHALLE
In this example, the Animal class is an abstract type with a pure virtual function speak(). The Dog and Cat
classes are derived classes that provide specific implementations of the speak() function.

Abstract types and pure virtual functions enable polymorphism, allowing you to write code that works with
objects of different derived classes through pointers or references to the abstract base class. This is a
powerful mechanism for achieving runtime polymorphism and code flexibility in C++.

Early Vs Late binding in cpp


In C++, binding refers to the process of connecting a function call to the actual function definition. There
are two types of binding in C++: early binding (also known as static binding or compile-time binding) and
late binding (also known as dynamic binding or runtime binding). These two binding mechanisms
determine when the decision about which function to call is made in your C++ code.

Early Binding (Static Binding):


Early binding occurs at compile time. In this case, the compiler determines which function to call based on
the static type of the object or reference used to make the call. The binding is resolved at compile time,
and the decision is fixed before the program is executed.

Example:

class Base {
public:
void show() {
std::cout << "Base class" << std::endl;
}
};

class Derived : public Base {


public:
void show() {
std::cout << "Derived class" << std::endl;
}
};

int main() {
Base obj1;
Derived obj2;
Base* ptr = &obj2;

obj1.show(); // Early binding, calls Base::show()


obj2.show(); // Early binding, calls Derived::show()
ptr->show(); // Early binding, calls Base::show() (based on the static type)
return 0;
}
25 NOTES BY A V MAHALLE
In this example, the decision on which show() method to call is made at compile time based on the static
type of the object or pointer.

Late Binding (Dynamic Binding):


Late binding occurs at runtime. In this case, the actual function to call is determined at runtime based on
the dynamic (actual) type of the object or reference. This mechanism is achieved by using virtual functions
and is commonly referred to as polymorphism.

Example:

class Base {
public:
virtual void show() {
std::cout << "Base class" << std::endl;
}
};

class Derived : public Base {


public:
void show() override {
std::cout << "Derived class" << std::endl;
}
};

int main() {
Base obj1;
Derived obj2;
Base* ptr = &obj2;

obj1.show(); // Early binding, calls Base::show()


obj2.show(); // Early binding, calls Derived::show()
ptr->show(); // Late binding, calls Derived::show() (based on the dynamic type)
return 0;
}

In this example, the show() method is marked as virtual, enabling late binding. When calling ptr->show(),
the decision about which function to call is determined at runtime based on the actual type of the object
pointed to by ptr, resulting in the call to Derived::show().

Late binding is a fundamental feature in achieving polymorphism and is commonly used when you want to
work with objects of derived classes through pointers or references to their base class, allowing for
flexibility and extensibility in your code.

26 NOTES BY A V MAHALLE

You might also like