C++之区分接口继承和实现继承(34)---《Effective C++》

1 篇文章 0 订阅
1 篇文章 0 订阅

条款34:区分接口继承和实现继承

接口继承和实现继承,即pure virtual和impure virtual或者non-virtual成员函数,现在我们可以查看如下代码:

class Shape{
public:
    virtual void draw() const=0;
    virtual void error(const std::string& msg);
    int objectID() const;
    ...
};
class Rectangle:public Shape{...};
class Ellipse:public Shape{...};
  • 声明一个pure virtual函数的目的是为了让derived classes只继承函数接口。

针对订购ModelC飞机,而其的飞行方式和Airplane所提供的飞行方式并不一样,我们通过在Airplane中定义接口,然后在每个Model中进行实现即可,即定义一个pure virtual函数声明,然后在各个子类中进行实现。

class Airplane{
public:
    virtual void fly(const Airport& destination)=0;
    ...
};
//提供pure virtual函数的缺省实现
void Airplane::fly(const Airport& destination){
    ...
}
class ModelA:public Airplane{
public:
    virtual void fly(const Airport& destination)
    {
        Airplane::fly(destination);
    }
    ...
};
class ModelB:public Airplane{
public:
    virtual void fly(const Airport& destination)
    {
        Airplane::fly(destination);
    }
    ...
};
class ModelC:public Airplane{
public:
    virtual void fly(const Airport& destnation);
    ...
};
void ModelC::fly(const Airport& destination)
{
    ...//定义C型飞机的自己的飞行实现
}

PS:pure virtual函数可以被定义,没想到吧!!!参看下代码:

#include <iostream>
#include <string>
using namespace std;
class Base{
public:
    Base(int x) :x(x){

    }
    virtual void mf0() = 0{
        cout << "hello,我是pure virtual函数,却可以被实现,Base::mf0(),没想到吧!!!" << endl;
    };

private:
    int x;
};
class Derived :public Base{
public:
    Derived(int x) :Base(x){

    }
    virtual void mf0(){
        cout << "hello,I'm the Derived's mf0()函数" << endl;
    }
};

int main(){
    Derived d(10);
    d.Base::mf0();
    d.mf0();
    return 0;
}

运行结果:
这里写图片描述

  • 声明impure virtual函数的目的是为了让derived classes继承该函数的接口和缺省实现。
class Airport{...};
class Airplane{
public:
    virtual void fly(const Airport& destination);
    ...
};
void Airplane::fly(const Airport& destination){
    ...
}
class ModelA:public Airplane{...};
class ModelB:publc Airplane{...};

但是此时公司又订了一批新的飞机ModelC,它的飞行方法和之前的飞行方法不一样,然而此时我们忘记为ModelC定义相应的fly方法了,因为有默认的实现呀!!!这样会导致ModelC出现极大灾难!

class ModelC:public Airplane{
    ...
};
Airport PDX(...);
Airplane* pa=new ModelC;
...
pa->fly(PDX);

为了避免这种问题,我们需要切断“impure virtual函数接口”和“默认实现”之间的连接,参看如下代码:

class Airplane{
public:
    virtual void fly(const Airport& destination)=0;
    ...
protected:
    void defaultFly(const Airport& destination);
};
void Airplane::defaultFly(const Airport& destination){
    ...
}
class ModelA:public Airplane{
public:
    virtual void fly(const Airport& destination){
        defaultFly(destnation);
    }
    ...
};
class ModelB:public Airplane{
public:
    virtual void fly(const Airport& destination)
    {
        defaultFly(destination);
    }
    ...
};
class ModelC:public Airplane{
public:
    virtual void fly(const Airport& destination){
        defaultfly(destination);
    }
    ...
};
void ModelC::defaultFly(const Airport& destination)
{
    ...//定义ModelC的飞行设计
}

这样的设计显然比以前的设计显得更可靠一些,至于Airplane::defaultFly,请注意其现在变成了protected,因为它是Airplane及其derived classes的实现细目,乘客应该只在意飞机怎么飞,不管它们怎么实现的。

  • 声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份强制性实现。

1、策略:pure virtual函数、impure virtual函数、non-virtual函数之间的差异,使你得以精确指定你想要derived classes继承的东西:只继承接口,或者继承接口和一份缺省实现,亦或是继承接口和一份强制实现,因此当你声明你的base classes的成员函数时候,需要谨慎选择,认真思考过后然后为base classes的成员函数进行属性配置。

2、常见错误:

  • 将所有函数声明为non-virtual,这样使得derived classes没有余域空间进行特化工作,non-virtual的析构函数尤其会带来问题。
  • 将所有成员函数声明为virtual,有时候这样做是正确的,然而这也可能是class设计者缺乏鉴定立场的前兆,某些函数就是不该在derived class中被重新定义,果真如此你应该将那些函数声明为non-virtual,没有人有权利妄称你的class适用于任何人任何事任何物他们只需花点时间重新定义你的函数就可以享受一切。

总结:
1)接口继承和实现继承不同,在public继承之下,derived classes总是继承base class的接口;
2)pure virtual函数只具体指定接口继承;
3)impure virtual函数具体指定接口继承及缺省实现继承。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
电子图书资源服务系统是一款基于 Java Swing 的 C-S 应用,旨在提供电子图书资源一站式服务,可从系统提供的图书资源中直接检索资源并进行下载。.zip优质项目,资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松copy复刻,拿到资料包后可轻松复现出一样的项目。 本人系统开发经验充足,有任何使用问题欢迎随时与我联系,我会及时为你解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(若有),项目具体内容可查看下方的资源详情。 【附带帮助】: 若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步。 【本人专注计算机领域】: 有任何使用问题欢迎随时与我联系,我会及时解答,第一时间为你提供帮助,CSDN博客端可私信,为你解惑,欢迎交流。 【适合场景】: 相关项目设计中,皆可应用在项目开发、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面中 可借鉴此优质项目实现复刻,也可以基于此项目进行扩展来开发出更多功能 【无积分此资源可联系获取】 # 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。积分/付费仅作为资源整理辛苦费用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值