D24.1.0 接口继承和实现继承

先给出一个类的定义:

class Shape
{
public:
    virtual void draw() const = 0;//纯虚(pure virtual)函数 
    virtual void error(const std::string& msg);//虚(impure virtual)函数
    int objectID() const;//普通函数
    ......
};

Shape是个抽象类,它的纯虚函数draw使它成为一个抽象class。所以客户不能够创建Shape类的实体,只能创建其派生类的实体。但是Shape会影响以public形式继承它的派生类。Shape类定义了三种类型的函数:纯虚函数、虚函数和普通函数。这些不同的声明带来了什么样的暗示呢?

纯虚函数:只继承函数接口

class Shape
{
public:
    virtual void draw() const = 0;
    //......
};

纯虚函数有两个突出的特性:1、必须在派生类中重新声明;2、它们在抽象类中通常没有定义。通过这两个性质大致明白,声明一个纯虚函数的目的是为了让派生类只继承函数的接口。例如,每种shape类型都是可绘制的,这是合理的要求。不过Shape不能为draw提供合理的缺省,毕竟椭圆的画法跟长方形的画法不一样。

纯虚函数在抽象类中通常不进行定义,但并不代表它不可以定义。在Shape类中可以微Shape::draw供应一份实现代码,只不过得使用类名进行调用。

Shape* ps = new Shape; //错误!Shape是抽象类
Shape* ps1 = new Rectangle;
ps1->draw();           //调用Rectangle::draw

Shape* ps2 = new Ellipse;
ps2->draw();           //调用Ellipse::draw

ps1->Shape::draw();//调用Shape::draw
ps2->Shape::draw();//调用Shape::draw

虚函数:继承函数接口和缺省(default)实现

虚函数在基类中有实现代码,派生类可能覆写它。声明非纯虚函数的目的是让派生类继承该函数的接口和缺省实现。

class Shape
{
public:
    virtual void error(const std::string& msg);//虚(impure virtual)函数
    ......
};

这个接口表示,每个类都必须支持一个error的函数,但是每个类可以自由处理错误。如果派生类不想针对错误做出任何特殊行为,则可以退回到Shape class提供缺省错误处理行为。也就是说Shape::error的声明式告诉派生类的设计者“你必须支持一个error函数,但如果你不想自己写一个可以使用Shape class提供缺省版本”。但是,允许非纯虚函数同时制定函数声明和函数缺省行为,有可能造成危险。

class Airplane
{
public:
    virtual Airplane::fly(const Airport& destination);
    //......
};

void Airplane::fly(const Airport& destination)
{
    //缺省代码,将飞机飞至指定的目的地
}

class ModelA : public Airplane {...};
class ModelB : public Airplane { ... };

为了表示所有飞机都一定能飞,并阐明“不同型飞机原则上需要不同的fly实现”,Airplane::fly被声明为virtual。为了避免在ModelA和ModelB中撰写相同代码,缺省飞行行为由Airplane::fly提供,它同时被ModelA和ModelB继承。

现在假设某公司决定购买一种新式C型,它的飞行方式不同。这个公司的程序员针对C型飞机添加了一个类,但是由于他们着急让新飞机上线服务,竟然忘记重新定义其fly函数:

Airpalne* pa = new ModelC;
pa->fly(AAA);  //调用Airplane::fly

这就可能酿成大灾难,试图以ModelA或者ModelB的飞行方式飞ModelC。如何解决这样的问题?

可以利用“纯虚函数必须在derived classes中重新声明,但它们也可以拥有自己的实现”。

class Airplane
{
public:
    virtual Airplane::fly(const Airport& destination) = 0;
    //......
};

void Airplane::fly(const Airport& destination)
{
    //缺省行为,将飞机飞至指定的目的地
}

class ModelC : public Airplane {
public:
    virtual Airplane::fly(const Airport& destination);
...};

void ModelC::fly(const Airport& destination)
{
    //将C型飞机飞至指定的目的地
}

将fly声明为纯虚函数使得ModelC类必须继承fly函数并改写。

普通函数(non-virtual):派生类继承接口以及强制实现

class Shape
{
public:
    int objectID() const;//普通函数
    ......
};

声明为non-virtual的函数只可以继承不能被改写,是一份强制性的实现。每个继承于Shape类的对象都有一个用来产生对象ID的函数,此ID是采用相同计算方法,任何派生类都不应该尝试改变其行为。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值