• C++面向对象高级编程(九)Reference与重载operator new和operator delete


    摘要: 技术在于交流、沟通,转载请注明出处并保持作品的完整性。


    一 Reference

    引用:之前提及过,他的主要作用就是取别名,与指针很相似,实现也是基于指针.

    1.引用必须有初值,且不能引用nullptr

    2.引用之后不能再引用别人

    3.引用通常不用于声明变量,多用于参数类型,和返回值类型

    见下面代码

    int main(int argc, const char * argv[]) {
    
        int x=0;
        
        //p is a pointer to x
        int* p = &x;
        
        // r is a reference to x
        int& r = x;
        
        //这个操作并不是r引用了别人而是 是r引用的x = 5
        int x2 = 5;
        r = x2; // x = 5
        
        cout << "x = "<< sizeof(x) << endl;
        cout << "r = "<< sizeof(r) << endl;
        cout << "r的地址 = "<< &r <<endl;
        cout << "p的地址 = "<< p <<endl;
        return 0;
    }

      输出结果

    你会发现 r的地址个p的地址是相同的,其实引用并没有实际的内存,为了实现引用的取别名的假象,编译器会这么做 sizeof(r) = sizeof(x)和 &x = &r

    4.引用是指针,是一种漂亮的指针

    void func2 (string* obj) { obj ->clear();} //pass by pointer
    void func1 (string  obj) { obj .clear();}  //pass by value
    void func3 (string& obj) { obj .clear();}  //pass by reference

    调用端

        string a;
        //pass by pointer 接口不同
        func2(&a);
        
        //pass by value 调用接口相同 效率低
        func1(a);
        
        //pass by reference 调用接口相同
        func3(a);

     5.不能用引用区分函数签名

    double imag(const double& im) {return im;};
    double imag(const double  im) {return im;};

     调用的时候你会发现

    错误提示是函数调用混淆,你会发现不能用引用区分函数签名(上面红色部分为函数签名)

    const也算函数签名的一部分


    二 多态

     带vaiturl  内存上会多一个4字节的指针

     继承是继承调用权 而不是继承内存大小

     动态绑定的三个前提

     1.必须通过指针调用

     2.指针为向上的关系(保证安全)

     3.调用的是虚函数

     (*(p->vptr)[n])(p));

     (*p->vptr[n])(p)


    三 const 

    a.const object(data member不得改变)

    b.non-const object(data member可以改变)

    c.const member function(保证不改变data member)

    d.non-const member functions(不保证 data member不变)

    他们的组合关系 

    当成员函数的const 和non-const版本同时存在,const object 只会调用const 版本,non-const object 只会调用non-const

    我们思考一下

    const String str("Hello world");
    str.print();

    如果print()不加const[const object与non-const member function] 会报错

    Copy On Write,带const 不用考虑 COW

    class template std::basic_string<...>
    
    //里面有两个member function 
    
    charT operator[] (size_type pos) const {不考虑COW == Copy On Write};
    
    reference operator[](size_type pos){必须考虑COW};

     四 New 和 Delete

    之前提过

    new   = malloc() + ctor

    delete = dtor + free()

    new 和delete不可以重载 但是 operator new 和 operator delete可以重载

    class Foo
    {
    public:
        
        Foo()
        {
            cout<< "Foo ("<< ++ctorNum << ")"<<endl;
        }
        ~Foo()
        {
            cout<< "~Foo ("<< ++dtorNum << ")"<<endl;
        }
        //重载成员operatpr new
        void* operator new(size_t size) noexcept
        {
            cout<< "Foo operator new" <<endl;
            
            return malloc(size);
        }
        //重载成员operatpr delete
        void operator delete(void* ptr, size_t size)
        {
            cout<< "Foo operator delete" <<endl;
            free(ptr);
        }
    }

      调用端

    int main()
    {
        Foo * p = new Foo;
        delete p;
    }

    结果

    发现我们接管了 operator new 和operator delete

    class Foo
    {
    public:
        
        Foo()
        {
            cout<< "Foo ("<< ++ctorNum << ")"<<endl;
        }
        ~Foo()
        {
            cout<< "~Foo ("<< ++dtorNum << ")"<<endl;
        }
        //重载成员operatpr new
        void* operator new[](size_t size)
        {
            cout<< "Foo operator new" <<endl;
            
            return malloc(size);
        }
        
        //重载成员operatpr delete[]
        void operator delete[](void* ptr, size_t size)
        {
            cout<< "Foo operator delete[]"<<endl;
            cout << size <<endl;
            free(ptr);
        }
        
        static int ctorNum;
        static int dtorNum;
    };
    
        int Foo::ctorNum = 0;
        int Foo::dtorNum = 0;

    调用端

    int main()
    {
        Foo* l = new Foo[5];
        delete[] l;
        return 0;
    }

     结果

    我们可以重载多个版本的class menber operator new() 第一参数必须为 size_t

    我们可以重载 class member operator delete() 可以重载过个版本 ,但是他们绝对不会被delete

    调用重载的delete()只有当new所调用的ctor抛出 exception 才会调用这些重载版的operator delete() 它只可能这样被调用,主要用归还未能完全城建成功的object所占用的 内存

    用会一一对应 ,如果你的delete()与new() 没有一一对应编译器  也不会报错 表示放弃对异常做处理放弃

       class Bad{};//抛出异常用
        class test
        {
        public:
            test(){}
            test(int i){/*故意抛出异常*/ throw Bad();}
            ~test(){}
            //一般的operator new()
            void* operator new(size_t size){cout<< "一般的operator new()" <<endl; return malloc(size);}
         //一般的operatpr delete
            void operator delete(void* ptr, size_t size){cout<< "一般的operator delete()"<<endl; free(ptr);}
            //标准库的operator new()
            void* operator new(size_t size, void* start){cout<< "标准库的operator new()" <<endl; return start;}
            //标准库的operator delete()
            void operator delete(void*, void*){cout<< "标准库operator delete(void*, void*)" <<endl;}
            //崭新的operator new()
            void* operator new(size_t size, long extra){cout<< "崭新operator new()" <<endl; return malloc(size + extra);}
            //崭新的operator new()
            void operator delete(void*, long){cout<< "崭新operator delete(void*, long)" <<endl;}
            //又一个operator new()
            void* operator new(size_t size, long extra, char init){cout<< "又一个operator new()" <<endl; return malloc(size + extra);}
            //又一个operator delete()
            void operator delete(void* size, long extra, char init){cout<< "又一个operator delete()" <<endl;} 
        };

      调用及输出

    int main()
    {
        try{
        test t;
        test* p1 = new test;
        test* p2 = new (&t) test;
        test* p3 = new(100) test;
        test* p4 = new(100,'a') test;
        test* p5 = new(100) test(1);
        test* p6 = new(100,'a') test(1);
        test* p7 = new(&t) test(1);
        }
        catch(...){};
        return 0;
    }

     

    发现new和delete是一一对应,至于其他的为什么没有打印出来是由于,new不成功抛出异常导致

    完!

    参照<<侯捷 C++面向对象高级编程>>

  • 相关阅读:
    Lua编程入门学习笔记1
    面向对象S.O.L.I.D原则
    asp.net Mvc学习之URL路由
    Spring 3.x MVC 入门2 通过示例初步感受spring mvc
    Spring 3.x MVC 入门1 图解MVC整体流程
    JSP自定义标签开发入门
    编译安装php5.3.8(含phpfpm)
    CentOS 安装eaccelerator PHP加速
    Nginx + fastcgi 处理php
    sql server charindex函数和patindex函数详解(转)
  • 原文地址:https://www.cnblogs.com/LearningTheLoad/p/7398347.html
Copyright © 2020-2023  润新知