一个类从另一个类派生属性和特征的能力称为继承。继承是面向对象编程最重要的特性之一。
**子类:**从另一个类继承属性的类称为子类或派生类。
**超类:**属性被子类继承的类称为基类或超类。
文章分为以下子主题:
- [为什么以及何时使用继承?](https://www.geeksforgeeks.org/inheritance-in-c/?ref=leftbar-rightbar#Why and when to use inheritance?)[继承方式](https://www.geeksforgeeks.org/inheritance-in-c/?ref=leftbar-rightbar#Modes of Inheritance)[继承类型](https://www.geeksforgeeks.org/inheritance-in-c/?ref=leftbar-rightbar#Types of Inheritance)
为什么以及何时使用继承?
考虑一组车辆。您需要为 Bus、Car 和 Truck 创建类。FuelAmount()、capacity()、applyBrakes() 方法对于所有三个类都是相同的。如果我们创建这些类避免继承,那么我们必须在三个类中的每一个中编写所有这些函数,如下图所示:
您可以清楚地看到上述过程导致相同代码重复 3 次。这增加了错误和数据冗余的机会。为了避免这种情况,使用了继承。如果我们创建一个Vehicle类并在其中编写这三个函数并从车辆类中继承其余的类,那么我们可以简单地避免数据重复并增加可重用性。看下图,其中三个类继承自车辆类:
使用继承,我们只需要编写一次函数而不是三次,因为我们从基类(Vehicle)继承了其余三个类。
在 C++ 中实现继承:为了创建从基类继承的子类,我们必须遵循以下语法。
语法:
class subclass_name : access_mode base_class_name { // 子类的主体 };
这里,subclass_name是子类的名称,access_mode是您想要继承该子类的模式,例如:public、private 等,base_class_name是您想要继承子类的基类的名称.
注意:派生类不会继承对私有数据成员的***访问权限。***但是,它确实继承了一个完整的父对象,其中包含该类声明的任何私有成员。
CPP
// C++ program to demonstrate implementation // of Inheritance #includeusing 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 << 'n'; cout << "Parent id is: " << obj1.id_p << 'n'; return 0; }
输出
孩子 id 是 7 父母 id 是 91
在上面的程序中,‘Child’ 类是从’Parent’ 类公开继承的,因此’Parent’ 类的公共数据成员也将由’Child’ 类继承。
继承方式
- 公共模式:如果我们从公共基类派生一个子类。然后基类的公共成员将在派生类中变为公共,而基类的受保护成员将在派生类中变为受保护。保护模式:如果我们从受保护的基类派生一个子类。然后基类的公共成员和受保护成员都将在派生类中受到保护。私有模式:如果我们从私有基类派生一个子类。然后基类的公共成员和受保护成员都将在派生类中变为私有。
**注意:**基类中的私有成员不能在派生类中直接访问,而受保护的成员可以直接访问。例如,类 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++ 中的继承类型
1. 单一继承:在单一继承中,一个类只能从一个类继承。即一个子类仅由一个基类继承。
语法:
class subclass_name : access_mode base_class { // 子类的主体 };
CPP
// C++ program to explain // Single inheritance #includeusing namespace std; // base class class Vehicle { public: Vehicle() { cout << "This is a Vehiclen"; } }; // 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, .... { // 子类的主体 };
在这里,基类的数量将用逗号(’,’)分隔,并且必须指定每个基类的访问模式。
CPP
// C++ program to explain // multiple inheritance #includeusing namespace std; // first base class class Vehicle { public: Vehicle() { cout << "This is a Vehiclen"; } }; // second base class class FourWheeler { public: FourWheeler() { cout << "This is a 4 wheeler Vehiclen"; } }; // 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; }
输出
这是一辆汽车 这是一辆四轮车
请访问此链接以详细了解多重继承。
3.多级继承:在这种类型的继承中,一个派生类是从另一个派生类创建的。
CPP
// C++ program to implement // Multilevel Inheritance #includeusing namespace std; // base class class Vehicle { public: Vehicle() { cout << "This is a Vehiclen"; } }; // first sub_class derived from class vehicle class fourWheeler: public Vehicle { public: fourWheeler() { cout << "Objects with 4 wheels are vehiclesn"; } }; // sub class derived from the derived base class fourWheeler class Car: public fourWheeler { public: Car() { cout << "Car has 4 Wheelsn"; } }; // main function int main() { // Creating object of sub class will // invoke the constructor of base classes. Car obj; return 0; }
输出
这是一个车辆 有 4 个轮子的对象是车辆 汽车有 4 个轮子
4. 层次继承:在这种类型的继承中,多个子类继承自一个基类。即多个派生类是从单个基类创建的。
CPP
输出
这是一辆车 这是一辆车
5.混合(虚拟)继承:混合继承是通过组合一种以上的继承来实现的。例如:结合层次继承和多重继承。
下图显示了分层继承和多重继承的组合:
CPP
// C++ program for Hybrid Inheritance #includeusing namespace std; // base class class Vehicle { public: Vehicle() { cout << "This is a Vehiclen"; } }; //base class class Fare { public: Fare() { cout << "Fare of Vehiclen"; } }; // 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.混合继承的一种特殊情况:多路径继承:
派生类有两个基类,而这两个基类有一个共同的基类,称为多路径继承。在这种类型的继承中可能会出现歧义。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrOFV35Q-1643543993815)(http://www.tutorialdost.com/Cpp-Programming-Tutorial/Images/Multipath-Inheritance-Ambiguity-In-Cpp.png)]
考虑以下程序:
CPP
// C++ program demonstrating ambiguity in Multipath // Inheritance #includeclass 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; }; int 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 << "n a from ClassC : " << obj.ClassC::a; cout << "n b : " << obj.b; cout << "n c : " << obj.c; cout << "n d : " << obj.d << 'n'; }
输出:
a 类 B : 10 a 类 C : 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的两个副本在 D 类。
有两种方法可以避免这种歧义:
使用范围解析运算符避免歧义:
使用范围解析运算符,我们可以手动指定访问数据成员 a 的路径,如上例中的语句 3 和 4 所示。
CPP
obj.ClassB::a = 10; ``// Statement 3``obj.ClassC::a = 100; ``// Statement 4
注意:仍然,ClassD 中有两个 ClassA 副本。
使用虚拟基类避免歧义:
CPP
#includeclass 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; }; int 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 << 'n'; }
输出:
a : 100 b : 20 c : 30 d : 40
根据上面的例子,ClassD 只有一个 ClassA 的副本,因此,语句 4 将覆盖在语句 3 中给出的 a 的值。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)