1、考虑下面的需求,软件处理动物,Cat与Dog需要特殊处理,因此,设计Cat和Dog继承Animal。Animal有copy赋值(不是虚方法),Cat和Dog也有copy赋值。考虑下面的情况:
Cat cat1;
Cat cat2;
Animal *a1 = &cat1;
Animal *a2 = &cat2;
*a1 = *a2;
思考*a1 = *a2会有什么问题? copy赋值不是虚方法,根据表面类型,调用Animal的copy赋值,这就导致所谓的部分赋值,cat2的Animal成分赋值给cat1的Animal成分,二者的Cat成分保持不变。

2、怎么解决上面的问题?
将Animal的copy赋值声明为virtual方法,如下:
virtual Animal& operator=(const Animal &rhs);
Cat和Dog重写:
virtual Cat& operator=(const Animal &rhs);
virtual Dog& operator=(const Animal &rhs);
这里使用了C++语言后期的一个特性,即协变,返回的引用更加具体。但是,对于形参表,重写必须保证保持一致。将copy赋值声明为virtual,解决了部分赋值的问题。但是,引入了一个新的问题。如下:
Cat cat;
Dog dog;
Animal* a1 = &cat;
Animal* a2 = &dog;
*a1 = *a2;
这是异型赋值,左边是Cat,右边是Dog。C++是强类型语言,一般情况下,异型赋值不合法,不会造成问题。但是,这种情况下导致异型赋值合法。对于指针解引用的情况,我们期望同型赋值是合法的,异型赋值是非法的。容易想到的办法是,在重写的copy赋值中,使用dynamic_cast进行同型判断。比如Cat的copy赋值,首先判断rhs是不是Cat,如果是,就赋值,如果不是,抛出异常。
我们知道,使用dynamic_cast效率低,考虑下面的情况,cat1 = cat2; 即使cat1与cat2的表面类型就是Cat,也会调用Cat& operator=(const Animal &rhs),进行一次dynamic_cast的运算,这不是我们所期望的。解决办法是:增加一个过载方法,编译器编译时,根据表面类型确定方法的调用。如下:Cat& operator=(const Cat &rhs)。同时对于重写的方法,可以调用前面的方法,如下:
Cat& operator=(const Animal &rhs)
{
return operator=(dynamic_cast<Cat&>(rhs));
}

3、运行期的类型检查,dynamic_cast的使用应该尽量避免。因为,首先效率低,其次,有些编译器还不支持dynamic_cast,不具有移植性。有没有更好的办法?
导致问题的原因是,对于指针解引用的赋值,父类的copy赋值不是虚方法,导致部分赋值。
因此,解决办法是,提取一个抽象类AbstractAnimal,将copy赋值声明为protected,子类可以调用,表面类型是抽象类的指针解引用赋值,不能调用。增加一个Animal类,继承AbstractAnimal。
对于抽象类,内部至少要有一个纯虚方法,很自然地将析构方法声明为纯虚方法。对于纯虚方法,需要注意:
a、纯虚方法意味着当前类为抽象类,不能实例化。
b、纯虚方法要求子类必须重写。
c、特别注意,纯虚方法一般不提供实现,但是允许提供实现,子类也可以调用。如果析构方法为纯虚方法,必须要提供实现。因为子类调用自身的析构方法后,必定会去调用父类的析构方法。

4、考虑,具体基类没有字段,是不是就不需要上述的抽象类了?这有两个问题,首先现在没有字段,以后可能会有字段,其次如果一个类没有字段,一开始就应该是一个抽象类。

5、结论,对于继承体系中的非尾端类,应该设计为抽象类,如果使用外界的程序库,需要做一下变通。

【M33】将非尾端类设计为抽象类相关推荐

  1. 条款M33:将非尾端类设计为抽象类:将抽象类赋值运算符函数设为protected

    1.常遇到的代码问题: class Animal { //抽象类 public: Animal& operator=(const Animal& rhs); virtual ~Anim ...

  2. More Effective C++之 Item M33:将非尾端类设计为抽象类

    假设你正在从事一个软件项目,它处理动物.在这个软件里,大多数动物能被抽象得非常类似,但两种动物--晰蜴和小鸡--需要特别处理.显然,晰蜴和小鸡与动物类的联系是这样的: 动物类处理所有动物共有的特性,晰 ...

  3. 建议收藏!全面梳理非交易类平台产品设计原则

    琳琅满目,光彩照人.这是现在商品世界的写照. 产能过剩,超额满足.这是当下社会现状的真实. 平台型产品,作为互联网的中坚力量,是我们普通用户透过网络触摸商品和社会的媒介. 可以说,每家公司都有一颗做平 ...

  4. 设计一个抽象类图形类,在该类中包含有至少两个抽象方法求周长和求面积,分别定义圆形类、长方形类、正方形类、三角形类来继承图形类,并实现上述两个方法

    设计一个抽象类图形类,在该类中包含有至少两个抽象方法求周长和求面积,分别定义圆形类.长方形类.正方形类.三角形类来继承图形类,并实现上述两个方法 设计抽象类 就要使用abstract关键字,抽象类中的 ...

  5. 面向对象之内置方法(简单)、组合。以及接口归一化设计与抽象类

    一.内置方法 一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo( ...

  6. abstract类_012 JAVA 抽象类、接口、String类的基础了解

    1.抽象方法和抽象类 抽象方法:使用abstract修饰的方法,没有方法体,只有声明.抽象方法可以当做是一种规范,让子类必须实现. 注意: 1.抽象方法没有方法体,只能以分号结尾 2.抽象方法只能声明 ...

  7. 面向对象的设计原则-类设计原则

    面向对象的设计原则-类设计原则 排行榜 收藏 打印 发给朋友 举报发布者:七月十五 热度票  浏览1368次 [共4条评论][我要评论]时间:2008年11月08日 10:55 在面向对象设计中,如何 ...

  8. 类设计原则及设计模式(一篇就够)

    类设计原则及设计模式 类设计的六大原则 设计模式定义 设计模式的分类 创建型模式 1. 简单工厂和工厂方法模式 定义和分类 2. 抽象工厂模式 3. 单例模式 定义 优缺点 饿汉式单例与懒汉式单例类比 ...

  9. 学习笔记:C++进阶【继承、多态、二叉树进阶、map和set、哈希、C++11、异常、智能指针、特殊类设计、C++的类型转换】

    文章目录 前言 一.继承 1. 继承的概念及定义 1.1 继承的概念 1.2 继承的定义 1.2.1 定义格式 1.2.2 继承关系和访问限定符 1.2.3 继承基类成员访问方式的变化 2. 基类和派 ...

最新文章

  1. android ScrollView/NestedScrollView 添加可拖动的滚动条
  2. c++, 派生类的构造函数和析构函数 , [ 以及operator=不能被继承 or Not的探讨]
  3. Global Mapper总汇
  4. 利用python进行统计及分析第7章,构建电影分类的dummies
  5. python将元组转换为列表_使用python将元组转换成列表,并替换其中元素
  6. DCN RepPoints解读
  7. 感想2-对于组件化的一些思考
  8. usermod命令 用户密码管理 mkpasswd命令
  9. git reset --hard命令小结
  10. 如何在 Apple TV 上获得电影推荐?
  11. mindspore-ResNet101使用GPU进行训练时报错
  12. gitee创建仓库,并将代码上传到gitee上
  13. P1095 [NOIP2007 普及组] 守望者的逃离
  14. 采用HTML,CSS,JAVASCRIPT的前端网页设计的内容展示
  15. FPS游戏通用准星修正实现自瞄
  16. iOS 6与iOS 7的增量更新的区别
  17. java 搭建个人博客_5分钟 教大家搭建免费个人博客
  18. 区块链的前世今生:为什么说区块链是即将到来的数字革命?
  19. kafka中leader和follower、AR、ISR、OSR、Controller的选举、为什么不能通过ZK的方式来选举partition的leader?
  20. java雷达数据解析_MSTAR雷达数据集总结

热门文章

  1. Codeforces Round #736 (Div. 2) C. Web of Lies
  2. 软银Pepper机器人有新工作了:在机场卖食物和啤酒
  3. 新一代的数据库SQL审计服务 - SQL洞察
  4. 微信退款 支付宝退款
  5. C# 访问SafeNet加密锁注意事项
  6. 公园导游图c语言课程设计,公园导游图.doc
  7. MOS管为什么会被静电击穿?
  8. iPhone软件开发之iDP使用,以及真机调试
  9. 详解HTTP协议和HTTPS协议
  10. 语音降噪_标准谱减法(附Python源码) @Learning Speech enhancement__1