• 【C++ Miscellany】继承体系非尾端类设计为抽象类


    部分赋值问题

    用软件来处理两种动物:蜥蜴和鸡

    class Animal
    {
    public:
    	Animal& operator = (const Animal& rhs);
    	...
    };
     
    class Lizard: public Animal
    {
    public:
    	Lizard& operator = (const Lizard& rhs);
    	...
    };
     
    class Chicken: public Animal
    {
    	Chicken& operator = (const Chicken& rhs);
    	...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    以下代码将导致只有“liz1的Animal成分”被修改,即部分赋值问题:

    Lizard liz1;
    d liz2;
     
    Animal* pAnimal1 = &liz1;
    Animal* pAnimal2 = &liz2;
    ...
    *pAnimal1 = *pAnimal2;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解决一:

    让赋值操作符成为虚函数

    class Animal
    {
    public:
    	virtual Animal& operator = (const Animal& rhs);
    	...
    };
     
    class Lizard: public Animal
    {
    public:
    	virtual Lizard& operator = (const Animal& rhs);
    	...
    };
     
    class Chicken: public Animal
    {
    	virtual Chicken& operator = (const Animal& rhs);
    	...
    };
    
    Lizard liz;
    Chicken chick;
     
    Animal* pAnimal1 = &liz;
    Animal* pAnimal2 = &chick;
    ...
    *pAnimal1 = *pAnimal2;	//任何类型的Animal出现在赋值动作的右边
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    如果Animal::operator=虚函数,先前的赋值行为就会调用正确的Lizard的操作符;缺点是:运行期间要进行所有类型的检验区分操作,于是使用dynamic_cast协助完成任务,但又会为动态判断付出复杂度和成本。

    解决二:

    将Animal设计为抽象类:

    • 允许Animal对象互相赋值
    • 禁止部分赋值和异型赋值
    • 派生类的赋值操作符可以调用基类的赋值操作符。
    class AbstractAnimal 
    { 
    protected:
     Animal& operator=(const Animal& rhs); 
     
    public: 
     virtual ~Animal() = 0; 
    }; 
    
    class Lizard: public Animal 
    { 
    public: 
     Lizard& operator=(const Lizard& rhs); 
    }; 
    
    class Chicken: public Animal 
    { 
    public: 
     Chicken& operator=(const Chicken& rhs); 
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    总结

    你发现自己需要产生一个具体类,继承自程序库的一个具体类,而你只能使用该程序库,不能修改,怎么办?

    1. 将你的具体类派生自既有的(程序库中的)具体类,但需要注意本条款一开始所验证的赋值相关问题等;
    2. 试着在程序库集成体系中找到更高的抽象类,其中有你需要的大部分功能,继承它;
    3. 以“你所希望继承的那个程序库类”来实现你的新类;
    4. 手上有什么就用什么。

    一般性的法则是:继承体系中的non-leaf(非尾端)类应该是抽象类。

  • 相关阅读:
    TMB1LTX 全新原装板卡12路高速任意业务汇聚波长转换板
    【Flink 实战系列】Flink on yarn 为什么 Allocated CPU VCores 显示不正确?
    css样式进行预处理
    架构案例分析重点
    蓝桥杯刷题|03普及-真题
    基于Python实现的特征选择的遗传算法(GA)
    为啥不适合,依然有很多人大张旗鼓搞企业内部开源?(下)
    八股文第十六天
    【Ubuntu-MySQL8安装与主从复制】
    云贝教育 |【DSI】Oracle数据库系列课-葵花宝典技术内幕实战课程
  • 原文地址:https://blog.csdn.net/weixin_49347928/article/details/133800144