C++ 中的继承

C++ 中的继承,第1张

C++ 中的继承

一个类从另一个类派生属性和特征的能力称为继承。继承是面向对象编程最重要的特性之一。
**子类:**从另一个类继承属性的类称为子类或派生类。
**超类:**属性被子类继承的类称为基类或超类。
文章分为以下子主题:

    [为什么以及何时使用继承?](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

#include 
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 << '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
#include
using 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
#include
using 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
#include
using 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

#include
using 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

#include

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;
};

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

#include

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;
};

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 的值。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5719006.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存