C++打怪 之 C++继承

2020-11-03 15:13:28 浏览数 (1)

1. 简介

继承 :表示两个类的关系,即通过已存在的类来创建一个新的类。其中已存在的类称为基类,新创建的类则称为派生类。

注:C 的继承类似于C语言中的结构体与结构体变量的关系:在C语言中,首先建立结构体以及其内部的结构体成员,然后以此结构体作为数据类型定义若干个结构体变量。如此一来,这些结构体变量就都包含了构建的结构体成员。

基类&派生类

由上面的介绍,基本了解了基类与派生类的概念以及关系。其中派生类可以源于一个或多个基类,即可以继承多个基类。形式如下:

代码语言:javascript复制
// class [派生类名]:[继承类型] [基类名]
class child-class: access-specifier parent-class 
{
 //<派生类体>
}

child-class表示派生类名;parent-class表示基类名;access-specifier表示继承类型,即public、protected和private三种之中的一个,若未声明,默认private类型。

代码语言:javascript复制
//E.g. 拷贝https://www.runoob.com/cplusplus/cpp-inheritance.html
#include <iostream>
 
using namespace std;
 
// 基类
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 派生类
class Rectangle: public Shape
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};


int main(void)
{
   Rectangle Rect;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;
 
   return 0;
}

输出:

代码语言:javascript复制
Total area: 35

访问权限与继承

基类也可以通过将成员权限声明为private,来保护成员不被派生类直接访问。列举一下访问权限关系:

访问

public

protected

private

同一个类

yes

yes

yes

派生类

yes

yes

no

外部的类

yes

no

no

一个派生类继承了所有的基类方法,但下列情况除外:

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。

继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

在实际编程中很少用到protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

公有继承(public): 当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。 私有继承(private): 当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

多继承

在上面也讲到一个类可以派生自多个基类,即多继承。派生类具备了所继承的多个基类的特性。语法:

代码语言:javascript复制
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
//<派生类类体>
};

看一下实际编程的使用:

代码语言:javascript复制
#include <iostream>
 
using namespace std;
 
// 基类 Shape
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 基类 PaintCost
class PaintCost 
{
   public:
      int getCost(int area)
      {
         return area * 70;
      }
};
 
// 派生类
class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};
 
int main(void)
{
   Rectangle Rect;
   int area;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
 
   area = Rect.getArea();
   
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;
 
   // 输出总花费
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;
 
   return 0;
}

输出:

代码语言:javascript复制
Total area: 35
Total paint cost: $2450

小结: 在这篇实例中可以发现,Rectangle类继承了 Shape类和PaintCost类,等同于Rectangle其内部包含了Shape类的width、height成员、setWidth(int w)、setHeight(int h)方法 和 PaintCost 中的getArea方法以及自己定义的getArea方法。相当于用较少的代码实现了一个集成多个父类特性的派生类。

总结

继承可以理解为编程中的偷懒技巧,例如当我要定义一个长方形对象,一个正方形对象,一个圆形对象,那么我们就将这三个对象的共同特性提取出来形成基类,不同的特性则放到自己的类中实现。从而使代码更简洁,同时方便后期代码的增加与维护。

0 人点赞