46-C++中的继承

发布时间:2021-05-12 浏览次数:72 次

一个类从另一个类派生属性和特性的能力称为继承。继承是面向对象编程的最重要功能之一。 

子类:从另一个类继承属性的类称为子类或派生类。 

父类:其属性被子类继承的类称为基类或类。 

本文分为以下子主题: 

  1. 为什么以及何时使用继承?

  2. 继承方式

  3. 继承类型

为什么以及何时使用继承?

考虑一组车辆。您需要为公交车,汽车和卡车创建类。对于这三个类,方法fuelAmount(),capacity(),applyBrakes()都是相同的。如果我们创建这些类以避免继承,则必须在三个类的每一个中编写所有这些函数,如下图所示: 

 

 

您可以清楚地看到,上述过程导致相同代码重复3次。这增加了错误和数据冗余的机会。为了避免这种情况,将使用继承。如果我们创建一个Vehicle类,并在其中编写这三个函数,并从Vehicle类继承其余类,那么我们可以简单地避免数据重复并提高可重用性。请看下图,其中三个类别是从车辆类别继承的:

 

使用继承,我们必须只编写函数一次,而不是编写函数三遍,因为我们已经从基类(Vehicle)继承了其余三个类。

在C ++中实现继承:要创建从基类继承的子类,我们必须遵循以下语法。 

语法: 

class subclass_name:access_mode base_class_name
{
     //子类的主体
};

在这里,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;
}

输出: 

小孩ID是7 家长编号是91

在上面的程序中,“孩子”类是从“父母”类公开继承的,因此,“孩子”类的公共数据成员也将被“孩子”类继承。

 继承方式

  1. 公共模式:如果我们从公共基类派生子类。然后,基类的公共成员将在派生类中成为公共成员,而基类的受保护成员将在派生类中成为受保护成员。 

  2. 保护模式:如果我们从保护的基类派生子类。然后,基类的公共成员和受保护的成员都将在派生类中受到保护。 

  3. 私有模式:如果我们从私有基类派生子类。然后,基类的公共成员和受保护的成员都将在派生类中变为私有成员。 

 

注意:无法直接在派生类中访问基类中的私有成员,而可以直接访问受保护的成员。例如,在下面的示例中,类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
{
  //子类的主体
};
// 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,....
{
  //子类的主体
};


在此,基类的数量将以逗号(',')分隔,并且必须为每个基类指定访问模式。 

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

输出: 

这是一辆车 这是一辆四轮车

3.多级继承:在这种继承类型中,从另一个派生类创建一个派生类。

// 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.层次继承:在这种继承中,一个基类继承了多个子类。即,从一个基类创建一个以上的派生类。

// 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.混合(虚拟)继承:混合继承是通过组合多种类型的继承来实现的。例如:组合层次继承和多重继承。 

下图显示了层次继承和多重继承的组合:

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

输出: 

这是一辆车 车费

6.混合继承的一种特殊情况:多路径继承: 

具有两个基类并且这两个基类具有一个公共基类的派生类称为多路径继承。这种类型的继承可能会引起歧义。 

 

考虑以下程序:  

// 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 << "\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;
}

输出: 

B类的A:10
来自ClassC的A: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
#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