• 第五十五课、经典问题解析四


    一、new和malloc、delete和free之间的区别

    1、new和malloc

    (1)、new关键字是c++的一部分

                malloc是c库提供的函数

    (2)、new是以具体类型为单位分配内存

                malloc是以字节为单位分配内存

    (3)、new在申请内存空间时可进行初始化

        malloc仅根据需要申请定量的内存空间

    (4)、new在所有c++编译器中都被支持

                malloc在某些系统开发中是不能调用的

    (5)、new能触发构造函数的调用

         malloc仅分配需要的内存空间

    (6)、对象的创建只能用new

           malloc不适合面向对象的开发

    2、delete和free

    (1)、delete在所有c++编译器中都被支持

                free在某些系统开发中是不能调用的

    (2)、delete能触发析构函数的调用

               free仅归还之前分配的内存空间

    (3)、对象的销毁只能用delete

         free不适合面向对象的开发

     

    #include<iostream>
    #include<cstdlib>//说明malloc和free是函数
    
    using namespace std;
    
    class Test
    {
    private:
        int *mp;
    public:
        Test()
        {
            mp = new int(100);
            cout << "Test()" << endl;
            cout << *mp << endl;
        }
        
        ~Test()
        {
            delete mp;
    cout
    << "~Test()" << endl; } }; int main() { Test* t1 = new Test();//会调用构造函数,不能用free来释放,否则可能造成内存泄漏 Test* t2 = (Test *)malloc(sizeof(Test));//只分配需要的内存空间,不会调用构造函数,不能用delete释放,否则会将mp指针错误释放掉

    delete t1;//调用析构函数 free(t2);//不会调用析构函数
    return 0; }

    二、构造函数、析构函数、虚函数、多态

    1、构造函数不可以成为虚函数

    (1)、在构造函数执行结束后,虚函数表指针才会被正确初始化

    2、析构函数可以成为虚函数

    (1)、建议在设计类时将析构函数声明为虚函数

    3、构造函数里面不可能发生多态行为

    (1)、构造函数执行时,虚函数表指针未被正确初始化

    4、析构函数里面不可能发生多态行为

    (1)、在析构函数执行时,虚函数表指针已被销毁

     

    #include<iostream>
    
    
    using namespace std;
    
    class Base
    {
    public:
        Base()// error, can not be declared virtual
        {
            cout << "Base()" << endl;
            func();//不会发生多态,调用当前类里面的func()
        }
        
        virtual void func()
        {
            cout << "Base::func()" << endl;
        }
        
        virtual ~Base()//can be declared virtual
        {
            cout << "~Base()" << endl;
            func();//只调用当前类定义的版本
        }
    };
    
    class Derived : public Base
    {
    public:
        Derived()
        {
            cout << "Derived()" << endl;
            func();
        }
        virtual void func()
        {
            cout << "Derived::func()" << endl;
        }
        virtual ~Derived()
        {
            cout << "~Derived()" << endl;
            func();
        }
    };
    
    int main()
    {
        Base* p = new Derived();//赋值兼容性原则
        
        cout << endl;
        
        delete p;//若析构函数不是虚函数,则这里就会只调用父类的构造函数,而不调用子类的,会造成内存泄漏
           //根据析构顺序,会先调用父类析构函数,然后调用子类析构函数
    return 0; } //打印结果 /* Base() Base::func() Derived() Derived::func() ~Derived() Derived::func() ~Base() Base::func() */

    三、继承中的强制类型转换

    1、dynamic_cast与继承相关的类型转换关键字

    2、dynamic_cast要求相关类中必须有虚函数

    3、用于有直接或间接继承关系的指针(引用)之间

    (1)、指针

    A、转换成功:得到目标类型的指针

    B、转换失败:得到一个空指针

    (2)、引用

    A、转换成功:得到目标类型的引用

    B、转换失败:得到一个异常操作信息

     

    #include<iostream>
    
    
    using namespace std;
    
    class Base
    {
    public:
        Base()
        {
            cout << "Base()" << endl;
        }
        
         virtual ~Base()//使用dynamic_cast需要类中有虚函数,故这里将析构函数声明为虚函数
        {
            cout << "~Base()" << endl;
        }
    };
    
    class Derived : public Base
    {
    };
    
    int main()
    {
        Base* p = new Base();
        
        Derived* d = dynamic_cast<Derived*>(p);//dynamic_cast 可以将子类转换转换成父类,反之不行(子类中可能有新成员),可以判断父子关系
        
       // Derived* p = new Derived();
        //Base* d = dynamic_cast<Base*> (p);//这样就会转换成功,输出succefully
        
        if(d != NULL)
        {
            cout << "succefully!" << endl;
        }
        else
        {
            cout << "error" << endl;//结果会输出这个,说明转换失败
        }
        
        cout << endl;
        
        delete p;
        return 0;
    }

    四、小结

    (1)、new/delete会触发构造函数或者析构函数的调用

    (2)、构造函数不能成为虚函数

    (3)、析构函数可以成为虚函数

    (4)、构造函数和析构函数里面不能产生多态的行为

    (5)、dynamic_cast 关键字是与继承相关

  • 相关阅读:
    jQuery1.9(辅助函数)学习之—— jQuery.param( obj ); 编辑
    jQuery1.9(辅助函数)学习之——.serialize();
    jQuery1.9(辅助函数)学习之——.serializeArray();
    聊聊 getClientRects 和 getBoundingClientRect 方法
    聊一聊数组的map、reduce、foreach等方法
    Typescript 接口(interface)
    配置 tsconfig.json
    Chrome 插件推荐
    Typescript 基础知识
    package.json
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6373548.html
Copyright © 2020-2023  润新知