基类和派生类
在之前,我们把具有相似状态和行为的事物归为一个类。而类和类也有相似之处,或者说,也有共同的特点,还可以继续向上抽象。
就比如说,圆形、三角形、矩形都是几何图形,都可以有一个背景颜色的属性,也可以有对颜色的getter和setter方法。
在上面的例子中,我们把几何图形类叫做基类(也称为父类或超类),把圆形类、三角形类、矩形类叫做几何图形类的派生类(也叫子类)。而这种父类和子类之间的关系就叫做继承,子类会继承父类的所有可访问的数据域和函数,同时也可以增加新的数据域和函数。
而继承的语法用上面的例子表示为:
class Circle: public GeometricObject {
//class body
};
就是说在原来的基础上加“: [权限] 父类”。
我们看下面的例子:父类是GeometricObject,子类有Circle和Rectangle
GeometricObject.h文件
#ifndef GEMOMETRICOBJECT_H #define GEMOMETRICOBJECT_H class GeometricObject { public: //无参构造函数 GeometricObject(); //有参构造函数,颜色为color GeometricObject(const string& color); //获取颜色 string getColor() const; //设置颜色 void setColor(); //对集合图形的描述 string toString() const; private: //几何图形的颜色 string color; }; #endif // GEMOMETRICOBJECT_H
Circle.h文件
#ifndef CIRCLE_H #define CIRCLE_H #include "GeometricObject.h" using namespace std;
class Circle: public GeometricObject { public: //无参构造函数 Circle(); //有参构造函数,颜色为color Circle(const string& color); //其他的属性和操作无需再写一遍,因为继承了GeometricObject类 //如果有需要可以再添加属性和方法等如下面的radius //获取圆的半径 double getRadius() const; //获取圆的面积 double getArea() const; private: //圆的半径 double radius; }; #endif // CIRCLE_H
Rectangle.h
#ifndef RECTANGLE_H #define RECTANGLE_H #include "GeometricObject.h"
using namespace std; class Rectangle: public GeometricObject { public: //无参构造函数 Circle(); //有参构造函数,颜色为color Circle(const string& color); //其他的属性和操作无需再写一遍,因为继承了GeometricObject类 //如果有需要可以再添加属性和方法等如下面的height和width //获取矩形的宽 double getWidth(); //获取矩形的高 double getHeight(); private: //矩形的高 double height; //矩形的宽 double width; }; #endif // RECTANGLE_H
这样一来,矩形类和圆形类就可以直接使用父类几何图形类的函数比如说toString,用来描述几何图形。
但是像toString()和getArea()这样的函数需要覆写,下面最后一部分会说到。
多重继承
C++不同于Java的单继承模式,允许多重继承。也就是说,一个子类可以继承自多个父类。
比如说鸟有会飞的和不会飞的(鸵鸟),我们可以将飞行和鸟作为两个抽象,鸟类中不提及飞行有关的属性或方法。而会飞行的鸟继承自鸟类和飞行类,不会飞行的鸟只继承自鸟类。
继承中的构造函数和析构函数
这里注意的只有一点:子类的构造函数会先调用父类的构造函数,父类的析构函数会先调用子类的析构函数。
举个例子:
假如我们在GeometricObject类的构造函数中加了一句:
cout << "我是一个几何图形" << endl;
那么每次创建圆形或者矩形实例的时候,都会打印一句:“我是一个几何图形”
函数覆写
函数覆写(也叫重写、重载、覆载,Override)的作用我们通过上面的例子来说明。
对于GeometricObject类的函数getArea(),由于不同的几何图形具有不同的求面积的方法,所以我们无法在GeometricObject类中具体地定义这个函数。我们应该把这个函数交给子类去实现,也就是说GeometricObject类中的getArea()函数没有函数体,而在Circle类和Rectangle类中有不同的函数体。这和我们后面要说到的虚函数和纯虚函数有关。
这样一来我们就可以实现使用同一个方法,但是内部逻辑却根据所处的子类而不同的目的。
在使用覆写过的虚函数时,优先使用子类的函数。