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方法。相当于用较少的代码实现了一个集成多个父类特性的派生类。
总结
继承可以理解为编程中的偷懒技巧,例如当我要定义一个长方形对象,一个正方形对象,一个圆形对象,那么我们就将这三个对象的共同特性提取出来形成基类,不同的特性则放到自己的类中实现。从而使代码更简洁,同时方便后期代码的增加与维护。