对于继承来说,有时候is-a规则并不是看上去的那么简单,比如正在开发一个图形程序,程序会显示圆和椭圆。椭圆有长轴和短轴两个数据成员,当长轴等于短轴时,就相当于是一个圆了。因此我们可以将椭圆类作为父类,圆类作为特殊的子类,但是这会带来一些问题。实际上圆并不需要两个数据成员来刻画,用一个半径就能够刻画了。
对于上面这种问题,我们可以从Ellipse(椭圆)和Circle(圆)类中抽象出它们的共性,将这些特性放到一个ABC(抽象基类)中。再从这个ABC类派生出Circle 和Ellispse类。
所谓抽象类,就是从别的类中抽出其共性而得到的,因此抽象类并不能被创建!!这很重要。
但是抽象类指针却可以指向其派生类,从而统一管理。在我们这个例子中就是BaseEllipse指针可以指向Circle和Ellipse。
BaseEllipse* p = nullptr;
p = new(Circle);
p->showAxis();
向上强制转换:将派生类引用或指针转换为基类引用或指针,使公有继承不需要进行显式类型转换。
向下强制转换:将基类引用或指针转换为派生类引用或指针,这是不合法的。因为is-a关系通常是不可逆的。简单的说,你不能保证基类一定能用派生类的方法。毕竟,如果可以的话,那干嘛还需要派生类?
纯虚函数的声明类似如下,就是在虚函数的基础上加个 = 0,这样的声明代表着该函数为空,即未定义,自然不用实现。实际上当一个类中存在一个纯虚函数时,这个类就变成了抽象类。
virtual double Area() const = 0;
注意:
(1)纯虚函数没有函数体;
(2)最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是虚函数”;
(3)这是一个声明语句,最后有分号。
以下为应用ABC的一个例子,小记一下要点把。
1.在基类中protectd中的内容,子类可以访问,但是外部访问不到。即如果 用Circle 实例化一个对象a ,a是访问不到setx的。
而在基类中的private,是更强的,子类不能访问,因此需要在基类中定义一些方法来让子类调用方法访问,因此在我的理解里protected 是用来方便开后门的。
2.上文所说只要基类拥有一个纯虚函数,该类就是一个抽象类了。对于继承抽象类的子类来说,其还是一个抽象类。??是不是很疑惑,确实是这样,但是是可以变成具体类的,但是要遵循一定的规则。
必须必须,对抽象类的纯虚函数进行改写。而且必须格式一样,如下所示。
1.纯虚函数
virtual double Area() const = 0;
2.1 错误重写(少了const)
virtual double Area(){return M_PI*_duanzhou*_duanzhou;};//这里是一个错误的例子,对纯虚函数的重写必须与其格式一致,这里少写了const,因此 Ellipse还是个抽象类。
2.2正确重写
virtual double Area()const{return M_PI*_duanzhou*_duanzhou;};//正确
3.注意这里子类的构造函数,对于自类而言,它只能赋值给自己的数据成员,对于基类private中的内容它是访问不到的。因此需要使用成员初始化列表传递给基类构造函数。下面提供了两种方式,请注意第一种,蛮有趣的。
//实现一
Circle::Circle(double r, double x, double y): _r(r), BaseEllipse(x,y){};
//实现二
Circle::Circle(double r, double x, double y):BaseEllipse(x,y) {
_r = r;
4.我写了一个重载加法,如下所示,刚开始脑抽把cir定义成 const Circle &cir了,结构cir怎么都访问不了其基类的public方法getx和gety。
因为对于const对象而言,它只能访问const类方法,所以不行。
5.脑抽++,刚开始写继承的时候写的是clss Circle:BaseEllipse,都没有写public,死活访问不到基类的方法。
Circle &Circle::operator+(Circle &cir) {
this->_r += cir._r;
//how to add the x and y
this->setx(cir.getx());//if const Circle &cir then I cannot use the BaseClass's public functions;
this->sety(cir.gety());
}
//
// Created by chenweiyu on 2022/3/30.
//
#ifndef CHAPTER13_BASEELLIPSE_H
#define CHAPTER13_BASEELLIPSE_H
#include
#include
#include
using std::cout;
using std::cin;
using std::endl;
using std::string;
class BaseEllipse {
private:
double _x;//中心x坐标
double _y;//中心y坐标
protected:
void setx(double x){
_x = x;
}
void sety(double y){
_y = y;
}
public:
double getx()const{return _x;};
double gety()const{return _y;} ;
virtual double Area() const = 0;
virtual ~BaseEllipse(){};
BaseEllipse(double x = 0,double y = 0){ _x = x; _y= y;};
void Move(double x,double y){ _x = x; _y = y;};
void showAxis() const{
cout<<"now the x is "<<_x<<" now the y is "<<_y<
下面是BaseEllipse.cpp中的代码,我基本都写了内联,所以这里的比较少。
//
// Created by chenweiyu on 2022/3/30.
//
#include "BaseEllipse.h"
Circle::Circle(double r, double x, double y): _r(r), BaseEllipse(x,y){};
Circle &Circle::operator+(Circle &cir) {
this->_r += cir._r;
//how to add the x and y
this->setx(cir.getx());//if const Circle &cir then I cannot use the BaseClass's public functions;
this->sety(cir.gety());
}