• 虚析构函数和容器继承


    虚析构函数


    在一个继承体系中,在继承链最顶端通常需要定义一个虚析构函数,即使它只是负责销毁资源而已:

    class Quete 
    {
    	public :
    		//
    		virtual ~Quete() = default;
    };
    
    class Bulk_quote : public Quote
    {
    	public :
    		~Bulk_quote() = default;
    };

    在上面的继承体系中, 基类定义了一个虚析构函数,是为了可以动态分配继承体系中的对象 :

    Quote* itemQ = new Quote;
    delete itemQ; // 调用Quote的析构函数
    itemQ = new Bulk_quote;
    delete itemQ; // 调用Bulk_quote的析构函数

    上面的代码里, delete一个动态申请的指针类型, 会进行动态绑定。编译器会依据指针的动态类型来执行相应版本的析构函数:

    在delete一个Quote类型指针时, itemQ的动态类型是Quote,因此会执行Quote的析构函数;

    在delete一个Bulk_quote类型指针时, itemQ的动态类型是Bulk_quote,因此会执行Bulk_quote的析构函数。


    虚析构函数机制能够确保我们在delete一个基类指针时能运行正确的析构函数版本

    如果基类的析构函数不是虚函数, 则delete一个指向派生类对象的基类指针将会产生未定义的行为


    对于一个不存在继承体系的类来说, 它需要一个虚构函数则它通常也需要定义自己的拷贝和赋值操作。 对于处于继承体系中的基类来说不遵循此规则, 它通常来说需要将自己的虚构函数定义为虚函数, 它为了成为一个虚函数而令内容为空, 因此无法推断它是否还需要拷贝或赋值操作。

    虚析构函数也会阻止合成移动操作。如果类需要移动操作, 需要自己定义移动操作。



    容器与继承


    容器继承典型的例子就是,在一个类型为基类类型的容器, 要同时存放基类对象和派生类对象,一般的做法是:

    std::vector<Quote> basket;
    // 插入一个基类对象
    basket.push_back(Quote("0-201-82470-1", 50));
    // 插入一个派生类对象, 但此派生类对象的派生类部分会被"切掉"
    basket.push_back(Bulk_quote("0-201-54848-8", 50, 10, 0.25));

    basket是一个存放基类Quote的vector容器, 添加完一个基类对象后, 继续添加一个派生类对象, 将一个派生类对象赋值给基类对象会"切掉"派生类部分,为了存储一个派生类对象, 做法是存放基类的指针类型,使用智能指针则是更好的选择:

    std::vector<std::shared_ptr<Quote>> basket;
    basket.push_back(make_shared<Quote>("0-201-82470-1", 50));
    basket.push_back(make_shared<Bulk_quote>("0-201-54848-8", 50, 10, 0.25));
    
    std::cout << basket.back()->net_price(15) << std::endl;

    可以将一个派生类指针转换为基类指针,同样也可以将派生类的智能指针转换为基类的智能指针。

    因为存放了基类指针类型, 因此在添加派生类对象后,并不会发生截断现象,在调用成员函数时,如果成员函数时虚函数,则依据基类指针的动态类型来执行相应的版本。 



  • 相关阅读:
    springboot雷神更新
    JVM整理文档
    这是我见过BIO/NIO/AIO讲的最清楚的博客了
    redis主从机制
    mybatis是如何防止sql注入的
    分布式锁的实现方式简介
    Nginx简介
    .net 下的集合
    C#模拟百度登录
    WPF 将PPT,Word转成图片
  • 原文地址:https://www.cnblogs.com/averson/p/5150002.html
Copyright © 2020-2023  润新知