一个类从另一个类派生特性和特征的能力称为继承。继承是面向对象编程的最重要功能之一。
子类:从另一个类继承属性的类称为子类或派生类。
超类:其属性被子类继承的类称为基类或超类。
本文分为以下子主题:
- 为什么以及何时使用继承?
- 继承方式
- 继承类型
为什么以及何时使用继承?
考虑一组车辆。你需要为公交车, 汽车和卡车创建类。对于这三个类, 方法fuelAmount(), capacity(), applyBrakes()都将相同。如果创建这些类以避免继承, 则必须在三个类的每一个中编写所有这些函数, 如下图所示:
你可以清楚地看到上述过程导致相同代码重复3次。这增加了错误和数据冗余的机会。为了避免这种情况, 将使用继承。如果我们创建一个Vehicle类并在其中编写这三个函数, 并从Vehicle类继承其余的类, 那么我们可以简单地避免数据重复并提高可重用性。请看下图, 其中三个类别是从车辆类别继承的:
使用继承, 我们必须只编写函数一次, 而不是编写函数三遍, 因为我们已经从基类(Vehicle)继承了其余三个类。
在C++中实现继承
注意:为了创建从基类继承的子类, 我们必须遵循以下语法。
语法:
class subclass_name : access_mode base_class_name
{
//body of subclass
};
这里,subclass_name是子类的名字,access_mode是你想继承这个子类的模式,例如:public, private等等,base_class_name是你想继承子类的基类的名字。
注意:派生类不继承对私有数据成员的访问。但是,它确实继承了一个完整的父对象,其中包含了该类声明的任何私有成员。
//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;
}
输出如下:
Child id is 7
Parent id is 91
在上述程序中, "儿童"类是从"父母"类中公开继承的, 因此"父母"类的公共数据成员也将由"儿童"类继承。
继承方式
- public模式:如果我们从公共基类派生子类。然后, 基类的公共成员将在派生类中成为公共成员, 而基类的受保护成员将在派生类中成为受保护成员。
- protected模式:如果我们从Protected基类派生子类。然后, 基类的公共成员和受保护的成员都将在派生类中受到保护。
- private模式:如果我们从Private基类派生子类。然后, 基类的公共成员和受保护的成员都将在派生类中变为私有成员。
注意 :无法在派生类中直接访问基类中的私有成员, 而可以直接访问受保护的成员。例如, 在下面的示例中, 类B, C和D都包含变量x, y和z。这只是访问的问题。
//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++中的继承类型
单继承:在单继承中, 一个类只能从一个类继承。即一个子类只能被一个基类继承。
语法:
class subclass_name : access_mode base_class
{
//body of subclass
};
//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 two 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;
}
输出如下:
This is a vehicle
多继承:多继承是c++的一个特性,一个类可以继承多个类。也就是说,一个子类是从多个基类继承来的。
语法:
class subclass_name : access_mode base_class1, access_mode base_class2, ....
{
//body of subclass
};
在此, 基类的数量将以逗号(', ')分隔, 并且必须为每个基类指定访问模式。
//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;
}
输出如下:
This is a Vehicle
This is a 4 wheeler Vehicle
请拜访这个链接以详细了解多重继承。
多级继承:在这种继承类型中, 从另一个派生类创建一个派生类。
//C++ program to implement
//Multilevel Inheritance
#include <iostream>
using namespace std;
//base class
class Vehicle
{
public :
Vehicle()
{
cout <<"This is a Vehicle" <<endl;
}
};
class fourWheeler: public Vehicle
{ public :
fourWheeler()
{
cout<<"Objects with 4 wheels are vehicles" <<endl;
}
};
//sub class derived from two base classes
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;
}
输出如下:
This is a Vehicle
Objects with 4 wheels are vehicles
Car has 4 Wheels
层次继承:在这种继承类型中, 一个基类继承了多个子类。即从一个基类创建一个以上的派生类。
//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;
}
输出如下:
This is a Vehicle
This is a Vehicle
混合(虚拟)继承:混合继承是通过组合多种类型的继承来实现的。例如:组合层次继承和多重继承。
下图显示了层次继承和多重继承的组合:
//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\n" ;
}
};
//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;
}
输出如下:
This is a Vehicle
Fare of Vehicle
混合继承的一种特殊情况:多路径继承:
具有两个基类且这两个基类具有一个公共基类的派生类称为多路径继承。这种类型的继承可能会引起歧义。
考虑以下程序:
//C++ program demonstrating ambiguity in Multipath Inheritance
#include<iostream.h>
#include<conio.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<<"\n A from ClassB : " <<obj.ClassB::a;
cout<<"\n A from ClassC : " <<obj.ClassC::a;
cout<<"\n B : " <<obj.b;
cout<<"\n C : " <<obj.c;
cout<<"\n D : " <<obj.d;
}
输出如下:
A from ClassB : 10
A from ClassC : 100
B : 20
C : 30
D : 40
在上面的示例中, ClassB和ClassC都继承了ClassA, 它们都具有ClassA的单个副本。但是, ClassD继承了ClassB和ClassC, 因此ClassD具有ClassA的两个副本, 一个副本来自ClassB, 另一个副本来自ClassC。
如果我们需要通过ClassD的对象访问ClassA的数据成员a, 则必须指定从中访问a的路径, 无论它是来自ClassB还是ClassC, bco'z编译器都无法区分ClassA的两个副本在ClassD中。
有两种方法可以避免这种歧义:
使用范围解析运算符
使用虚拟基类
使用范围解析运算符避免歧义:
使用作用域解析运算符, 我们可以手动指定从中访问数据成员a的路径, 如上例中的语句3和4所示。
obj.ClassB::a = 10; //Statement 3
obj.ClassC::a = 100; //Statement 4
注意:仍然在ClassD中有ClassA的两个副本。
使用虚拟基类避免歧义:
#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<<"\n A : " <<obj.a;
cout<<"\n B : " <<obj.b;
cout<<"\n C : " <<obj.c;
cout<<"\n D : " <<obj.d;
}
输出如下:
A : 100
B : 20
C : 30
D : 40
根据上面的示例, ClassD只有ClassA的一个副本, 因此, 语句4将覆盖语句3中给出的a的值。
被认为是行业中最受欢迎的技能之一, 我们拥有自己的编码基础C++ STL通过激烈的问题解决过程来训练和掌握这些概念。