• 【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(非尾端)类应该是抽象类。

  • 相关阅读:
    【论文精读】Diffusion Transformer(DiT)
    内存模型与C++ 内存序
    ssh 公钥和密钥
    SpringBoot项目自定义注解实现RBAC权限校验
    Human-level control through deep reinforcement learning
    python技术面试题(其三)
    Edge浏览器下载文件提示 “无法安全下载” 的解决方法
    走进苏州的开源创新之旅:开放原子开源大赛苏州站系列活动启幕
    【王道数据结构编程题】- 二叉树编程练习
    12、初识表单POST和get提交
  • 原文地址:https://blog.csdn.net/weixin_49347928/article/details/133800144