zoukankan      html  css  js  c++  java
  • C++回顾day03---<纯虚函数和抽象类以及虚析构函数,delete使用>

    一:纯虚函数和抽象类

    纯虚函数是一个在基类中说明的虚函数,在基类中没有定义,要求任何派生类都定义自己的版本
    纯虚函数为各个派生类提供一个公共接口
    纯虚函数的形式:
    virtual 类型 函数名(参数列表)=0;
    一个具有纯虚函数的基类称为抽象类
    注意:抽象类不能实例化对象
    一个派生类继承抽象类但是未实现纯虚函数,则也变为抽象类,可以继续被继承实现
    class Parent    //抽象类
    {
    public:
        Parent()
        {
            cout << "Parent construct" << endl;
        }
    
        virtual void overrideFunc() = 0;    //纯虚函数
    };
    
    class Child01:public Parent  //未实现纯虚函数,所以还是一个抽象类,不能被实例化对象,可以被继承
    {
    public:
        Child01()
        {
            cout << "Child01 construct" << endl;
        }
    };
    
    class Child02 :public Parent  //未实现纯虚函数,是抽象类,可以被继承实现
    {
    public:
        Child02()
        {
            cout << "Child02 construct" << endl;
        }
    };
    
    class ChildSon :public Child01
    {
    public:
        ChildSon()
        {
            cout << "ChildSon construct" << endl;
        }
    
        virtual void overrideFunc()  //实现了纯虚函数,是一个可以实例化对象的类
        {
            cout << "ChildSon finish" << endl;
        }
    };
    
    void main()
    {
        ChildSon c;
        system("pause");
    }

    二:虚析构函数

    (0)注意:构造函数不能是虚函数:建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数

    (一)问题引出:未使用虚析构函数时会出现内存泄漏(当父类指针指向子类对象时)

    class Parent    //抽象类
    {
    public:
        char *name;
    public:
        Parent(char* n)
        {
            name = (char *)malloc(strlen(n) + 1);
            strcpy(name, n);
            cout << "Parent construct" << endl;
        }
    
        virtual void getInfo()
        {
            cout << "parent name:" << this->name << endl;
        }
    
        ~Parent()
        {
            cout << "Parent distruct" << endl;
            if (this->name)
            {
                delete this->name;
                this->name = NULL;
            }
        }
    };
    
    class Child01:public Parent
    {
    public:
        char *addr;
    public:
        Child01(char* n, char* a) :Parent(n)
        {
            addr = (char *)malloc(strlen(a) + 1);
            strcpy(addr, a);
            cout << "Child01 construct" << endl;
        }
    
        virtual void getInfo()
        {
            cout << "child01 name:" << this->name << endl;
            cout << "child01 addr:" << this->addr << endl;
        }
    
        ~Child01()
        {
            cout << "Child01 distruct" << endl;
            if (this->name)
            {
                delete name;
                this->name = NULL;    //释放后置空,是一个良好的习惯
            }
            if (this->addr)
            {
                delete addr;
                this->addr = NULL;
            }
        }
    };
    
    
    void main()
    {
        Parent* p = new Child01("Liu","zz");
    
        delete p;  //会根据父类指针去调用父类析构函数:回顾前面多态
        
        system("pause");
    }

    发现只调用了父类析构函数,释放了name变量,但是addr变量并没有进行释放,导致了内存泄漏

    (二)问题解决:联系前面多态,使用虚析构函数--->会根据虚函数指针找到虚函数表从而调用子类析构函数(而)子类析构时候同构造相反方向去调用基类析构方法《重点》

    class Parent    //抽象类
    {
    public:
        char *name;
    public:
        Parent(char* n)
        {
            name = (char *)malloc(strlen(n) + 1);
            strcpy(name, n);
            cout << "Parent construct" << endl;
        }
    
        virtual void getInfo()
        {
            cout << "parent name:" << this->name << endl;
        }
    
        virtual ~Parent()
        {
            cout << "Parent distruct" << endl;
            if (this->name)
            {
                delete this->name;
                this->name = NULL;
            }
        }
    };
    
    class Child01:public Parent
    {
    public:
        char *addr;
    public:
        Child01(char* n, char* a) :Parent(n)
        {
            addr = (char *)malloc(strlen(a) + 1);
            strcpy(addr, a);
            cout << "Child01 construct" << endl;
        }
    
        virtual void getInfo()
        {
            cout << "child01 name:" << this->name << endl;
            cout << "child01 addr:" << this->addr << endl;
        }
    
        virtual ~Child01()
        {
            cout << "Child01 distruct" << endl;
            if (this->name)
            {
                delete name;
                this->name = NULL;    //释放后置空,是一个良好的习惯
            }
            if (this->addr)
            {
                delete addr;
                this->addr = NULL;
            }
        }
    };
    
    void testfunc()
    {
        Parent* p = new Child01("Liu","zz");
    
        delete p;
    }
    
    void main()
    {
        testfunc();
        
        system("pause");
    }

     

    三:回顾delete运算符

    (一)注意:在C中使用malloc和free函数来分配和释放内存,在C++中扩展了new和delete运算符 

    (二)其中new和delete运算符使用:

    new运算符的使用:
    
    指针变量 = new 类型(常数);
    指针变量 = new 类型[表达式];
    delete运算符的使用:
    
    delete 指针变量
    delete []指针变量

    (三)重点:delete中使用的指针变量必须是一个new返回的指针变量《重点》

    正确使用:

        Parent* p = new Child01("Liu","zz");
    
        delete p;

    错误使用:

        Child01 c("Liu", "zz");
        Parent* p = &c;
    
        delete p;

  • 相关阅读:
    %u编码
    总结
    windows7 安装PHP7 本地网站搭建
    统计某个端口的链接数
    mysql连结查询
    mysql in
    读书笔记<白帽子讲web安全>
    Web攻防系列教程之文件上传攻防解析(转载)
    攻防:文件上传漏洞的攻击与防御
    weblogic检查项
  • 原文地址:https://www.cnblogs.com/ssyfj/p/10777237.html
Copyright © 2011-2022 走看看