Наследование в C ++
Способность класса извлекать свойства и характеристики из другого класса называется наследованием . Наследование - одна из наиболее важных функций объектно-ориентированного программирования.
Подкласс: класс, наследующий свойства от другого класса, называется подклассом или производным классом.
Суперкласс: класс, свойства которого наследуются подклассом, называется базовым классом или суперклассом.
Статья разбита на следующие подтемы:
- Зачем и когда использовать наследование?
- Способы наследования
- Типы наследования
Зачем и когда использовать наследование?
Рассмотрим группу автомобилей. Вам нужно создать классы для автобусов, автомобилей и грузовиков. Методы fuelAmount (), capacity (), applyBrakes () будут одинаковыми для всех трех классов. Если мы создадим эти классы, избегая наследования, тогда мы должны написать все эти функции в каждом из трех классов, как показано на рисунке ниже:
Вы можете ясно видеть, что приведенный выше процесс приводит к дублированию одного и того же кода 3 раза. Это увеличивает вероятность ошибки и избыточности данных. Чтобы избежать такой ситуации, используется наследование. Если мы создадим класс Vehicle и напишем в него эти три функции и унаследуем остальные классы от класса транспортного средства, то мы сможем просто избежать дублирования данных и увеличить возможность повторного использования. Посмотрите на диаграмму ниже, на которой три класса унаследованы от класса транспортного средства:
Используя наследование, мы должны писать функции только один раз, а не трижды, поскольку мы унаследовали остальные три класса от базового класса (Vehicle).
Реализация наследования в C ++ : для создания подкласса, унаследованного от базового класса, мы должны следовать синтаксису ниже.
Синтаксис :
class subclass_name: access_mode base_class_name { // тело подкласса };
Here, subclass_name is the name of the sub class, access_mode is the mode in which you want to inherit this sub class for example: public, private etc. and base_class_name is the name of the base class from which you want to inherit the sub class.
Note: A derived class doesn’t inherit access to private data members. However, it does inherit a full parent object, which contains any private members which that class declares.
CPP
// C++ program to demonstrate implementation // of Inheritance #include <bits/stdc++.h> using namespace std; //Base class class Parent { public : int id_p; }; // Sub class inheriting from Base Class(Parent) class Child : public Parent { public : int id_c; }; //main function int main() { Child obj1; // An object of class child has all data members // and member functions of class parent obj1.id_c = 7; obj1.id_p = 91; cout << "Child id is " << obj1.id_c << endl; cout << "Parent id is " << obj1.id_p << endl; return 0; } |
Выход:
Идентификатор ребенка - 7 Родительский идентификатор 91
В приведенной выше программе класс «Дочерний» публично наследуется от класса «Родитель», поэтому открытые члены данных класса «Родитель» также будут унаследованы классом «Дочерний».
Способы наследования
- Открытый режим : если мы производим подкласс из общедоступного базового класса. Тогда открытый член базового класса станет общедоступным в производном классе, а защищенные члены базового класса станут защищенными в производном классе.
- Защищенный режим : если мы производим подкласс от защищенного базового класса. Тогда как открытый член, так и защищенные члены базового класса станут защищенными в производном классе.
- Частный режим : если мы производим подкласс из частного базового класса. Тогда как открытый, так и защищенный члены базового класса станут частными в производном классе.
Note : The private members in the base class cannot be directly accessed in the derived class, while protected members can be directly accessed. For example, Classes B, C and D all contain the variables x, y and z in below example. It is just question of access.
CPP
// C++ Implementation to show that a derived class // doesn’t inherit access to private data members. // However, it does inherit a full parent object class A { public : int x; protected : int y; private : int z; }; class B : public A { // x is public // y is protected // z is not accessible from B }; class C : protected A { // x is protected // y is protected // z is not accessible from C }; class D : private A // "private" is default for classes { // x is private // y is private // z is not accessible from D }; |
В приведенной ниже таблице резюмируются указанные выше три режима и показаны спецификаторы доступа для членов базового класса в подклассе, когда они производятся в общедоступном, защищенном и частном режимах:
Типы наследования в C ++
1. Одиночное наследование . При одиночном наследовании классу разрешено наследование только от одного класса. т.е. один подкласс наследуется только одним базовым классом.
Syntax:
class subclass_name : access_mode base_class { //body of subclass };
CPP
// C++ program to explain // Single inheritance #include <iostream> using namespace std; // base class class Vehicle { public : Vehicle() { cout << "This is a Vehicle" << endl; } }; // sub class derived from a single base classes class Car: public Vehicle{ }; // main function int main() { // creating object of sub class will // invoke the constructor of base classes Car obj; return 0; } |
Выход:
Это автомобиль
2. Множественное наследование. Множественное наследование - это функция C ++, в которой класс может наследовать от нескольких классов. т.е. один подкласс наследуется более чем от одного базового класса .
Синтаксис :
class subclass_name: access_mode base_class1, access_mode base_class2, .... { // тело подкласса };
Here, the number of base classes will be separated by a comma (‘, ‘) and access mode for every base class must be specified.
CPP
// C++ program to explain // multiple inheritance #include <iostream> using namespace std; // first base class class Vehicle { public : Vehicle() { cout << "This is a Vehicle" << endl; } }; // second base class class FourWheeler { public : FourWheeler() { cout << "This is a 4 wheeler Vehicle" << endl; } }; // sub class derived from two base classes class Car: public Vehicle, public FourWheeler { }; // main function int main() { // creating object of sub class will // invoke the constructor of base classes Car obj; return 0; } |
Выход:
Это автомобиль Это 4-х колесный автомобиль.
Посетите эту ссылку, чтобы подробнее узнать о множественном наследовании.
3. Многоуровневое наследование . В этом типе наследования производный класс создается из другого производного класса.
CPP
// C++ program to implement // Multilevel Inheritance #include <iostream> using namespace std; // base class class Vehicle { public : Vehicle() { cout << "This is a Vehicle" << endl; } }; // first sub_class derived from class vehicle class fourWheeler: public Vehicle { public : fourWheeler() { cout<< "Objects with 4 wheels are vehicles" <<endl; } }; // sub class derived from the derived base class fourWheeler class Car: public fourWheeler{ public : car() { cout<< "Car has 4 Wheels" <<endl; } }; // main function int main() { //creating object of sub class will //invoke the constructor of base classes Car obj; return 0; } |
Выход:
Это автомобиль Объекты с 4 колесами являются транспортными средствами. Автомобиль имеет 4 колеса
4. Иерархическое наследование . В этом типе наследования более одного подкласса наследуется от одного базового класса. т.е. из одного базового класса создается более одного производного класса.
CPP
// C++ program to implement // Hierarchical Inheritance #include <iostream> using namespace std; // base class class Vehicle { public : Vehicle() { cout << "This is a Vehicle" << endl; } }; // first sub class class Car: public Vehicle { }; // second sub class class Bus: public Vehicle { }; // main function int main() { // creating object of sub class will // invoke the constructor of base class Car obj1; Bus obj2; return 0; } |
Выход:
Это автомобиль Это автомобиль
5. Гибридное (виртуальное) наследование . Гибридное наследование реализуется путем объединения более одного типа наследования. Например: сочетание иерархического наследования и множественного наследования.
На изображении ниже показано сочетание иерархического и множественного наследования:
CPP
// C++ program for Hybrid Inheritance #include <iostream> using namespace std; // base class class Vehicle { public : Vehicle() { cout << "This is a Vehicle" << endl; } }; //base class class Fare { public : Fare() { cout<< "Fare of Vehicle
" ; } }; // first sub class class Car: public Vehicle { }; // second sub class class Bus: public Vehicle, public Fare { }; // main function int main() { // creating object of sub class will // invoke the constructor of base class Bus obj2; return 0; } |
Выход:
Это автомобиль Стоимость транспортного средства
6. Частный случай гибридного наследования: Многопутевое наследование :
Производный класс с двумя базовыми классами, и эти два базовых класса имеют один общий базовый класс, называется многопутевым наследованием. В этом типе наследования может возникнуть двусмысленность.
Consider the following program:
CPP
// C++ program demonstrating ambiguity in Multipath // Inheritance #include <conio.h> #include <iostream.h> class ClassA { public : int a; }; class ClassB : public ClassA { public : int b; }; class ClassC : public ClassA { public : int c; }; class ClassD : public ClassB, public ClassC { public : int d; }; void main() { ClassD obj; // obj.a = 10; //Statement 1, Error // obj.a = 100; //Statement 2, Error obj.ClassB::a = 10; // Statement 3 obj.ClassC::a = 100; // Statement 4 obj.b = 20; obj.c = 30; obj.d = 40; cout << "
A from ClassB : " << obj.ClassB::a; cout << "
A from ClassC : " << obj.ClassC::a; cout << "
B : " << obj.b; cout << "
C : " << obj.c; cout << "
D : " << obj.d; } |
Выход:
A из класса B: 10 A из класса C: 100 А: 20 С: 30 Д: 40
In the above example, both ClassB & ClassC inherit ClassA, they both have single copy of ClassA. However ClassD inherit both ClassB & ClassC, therefore ClassD have two copies of ClassA, one from ClassB and another from ClassC.
If we need to access the data member a of ClassA through the object of ClassD, we must specify the path from which a will be accessed, whether it is from ClassB or ClassC, bco’z compiler can’t differentiate between two copies of ClassA in ClassD.
There are 2 ways to avoid this ambiguity:
Avoiding ambiguity using scope resolution operator:
Using scope resolution operator we can manually specify the path from which data member a will be accessed, as shown in statement 3 and 4, in the above example.
CPP
obj.ClassB::a = 10; //Statement 3 obj.ClassC::a = 100; //Statement 4 |
Note : Still, there are two copies of ClassA in ClassD.
Avoiding ambiguity using virtual base class:
CPP
#include<iostream.h> #include<conio.h> class ClassA { public : int a; }; class ClassB : virtual public ClassA { public : int b; }; class ClassC : virtual public ClassA { public : int c; }; class ClassD : public ClassB, public ClassC { public : int d; }; void main() { ClassD obj; obj.a = 10; //Statement 3 obj.a = 100; //Statement 4 obj.b = 20; obj.c = 30; obj.d = 40; cout<< "
A : " << obj.a; cout<< "
B : " << obj.b; cout<< "
C : " << obj.c; cout<< "
D : " << obj.d; } |
Выход:
А: 100 А: 20 С: 30 Д: 40
Согласно приведенному выше примеру ClassD имеет только одну копию ClassA, поэтому оператор 4 перезапишет значение a, заданное в операторе 3.
Автор статьи - Харш Агарвал. Если вам нравится GeeksforGeeks, и вы хотели бы внести свой вклад, вы также можете написать статью на сайте deposit.geeksforgeeks.org или отправить свою статью по электронной почте: grant@geeksforgeeks.org. Посмотрите, как ваша статья появляется на главной странице GeeksforGeeks, и помогите другим гикам.