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++面向对象高级编程>>

时间: 2024-09-30 00:11:49

C++面向对象高级编程(九)Reference与重载operator new和operator delete的相关文章

C++面向对象高级编程(二)

版权声明:本文为博主原创文章,未经博主允许不得转载. 接下来的几篇文章,我将回忆一下C++的基础. C++的由两部分组成 1.C++语言 2.C++标准库 本篇文章主要分享我学习C++语言的笔记. 这次主要回忆一下操作符重载. 先看一段代码,后续我会介绍这么做的原由 #include <iostream> class complex { public: complex(double r = 0, double i = 0) : re(r) ,im(i) {} complex& oper

C++面向对象高级编程(七)point-like classes和function-like classes

技术在于交流.沟通,转载请注明出处并保持作品的完整性. 1.pointer-like class 类设计成指针那样,可以当做指针来用,指针有两个常用操作符(*和->),所以我们必须重载这两个操作 /*简单实现一下智能指针的*与 -> 操作符*/ template <class T> class shared_ptr_test { public: T& operator* () const //重载* { return *px; } T* operator->() co

Boolan C++面向对象高级编程学习第五周

本周C++面向对象高级编程编程主要是讲三个方面 1.虚表和虚指针 虚指针:如果类(包括父类)中有虚函数,就一定会有虚指针,虚指针是指向虚函数的虚表. 虚表:虚指针指向的一种类的表,表上存有类里面虚函数的实现的指针 这里虚函数和虚表一般是和类的多太性结合在一起来使用的,子类调用虚函数是通过调用虚指针来调用虚函数表里面的指针再来实现函数特性 这种调用的方式叫做动态绑定,是一种通过指针类型自动来判断调用的对象,在实现中可以不用区分哪个对象从而调用对应的函数 我们普通的调用类里面的函数叫做静态绑定 2.

Python3 面向对象 高级编程

正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.  class Student(object): pass 然后,尝试给实例绑定一个属性: >>> s = Student() >>> s.name = 'Michael' # 动态给实例绑定一个属性 还可以尝试给实例绑定一个方法: >>> def set_age(self, age): # 定义一个函数作为实例方法 ...

C++面向对象高级编程(六)转换函数与non-explicit one argument ctor

技术在于交流.沟通,转载请注明出处并保持作品的完整性. 1.conversion function 转换函数 //1.转换函数 //conversion function //只要你认为合理 你可以任意写转换函数 class Fraction { public: Fraction(int num, int den = 1):m_numerator(num),m_denominator(den){} operator double() const //注意看 没有返回类型,这个编译器会帮做,且防止

C++面向对象高级编程(三)

版权声明:本文为博主原创文章,未经博主允许不得转载. 接下来的几篇文章,我将回忆一下C++的基础. C++的由两部分组成 1.C++语言 2.C++标准库 本篇文章主要分享我学习C++语言的笔记. 本节主要介绍 Big Three 即析构函数,拷贝构造函数,赋值拷贝函数,前面主要围绕不带指针的class complex本节中主要围绕带指针的String类 前面我说过如果你创建的类不带有指针,那么多半你可以不用写析构函数,但是如果你创建了一个带指针的类,那么你必须重写Big Three 创建一个类

[7]面向对象高级编程

[7]面向对象高级编程 数据封装.继承和多态只是面向对象程序设计中最基础的3个概念.在Python中,面向对象还有很多高级特性,允许我们写出非常强大的功能. 我们会讨论多重继承.定制类.元类等概念. 使用__slots__ 正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性.先定义class: >>> class Student(object): ... pass ... 然后,尝试给实例绑定一个属性: >

python基础-面向对象高级编程

实例化对象绑定属性 s.name = 'Michael' # 动态给实例绑定一个属性 类绑定方法---所有实例化对象均可调用Student.set_score = set_score 实例化对象绑定方法---只有该对象可调用from types import MethodType#绑定方法需要使用MethodTypes.set_age = MethodType(set_age, s) # 给实例绑定一个方法 Python内置的@property装饰器就是负责把一个方法变成属性调用的把一个gett

C++面向对象高级编程(下) 第二周笔记 GeekBand

1.vptr和vtbl 当存在虚函数就会出现虚指针vptr指向虚函数所在位置vtbl 将vptr实现vtbl内容翻译为C: (*p->vptr)n; (* p->vptr[n])(p); 动态绑定: 虚机制 1.指针 2.向上转型保证安全 3.调用的是虚函数 2.this指针 [Template Method] This->Serialize()实现: (*(this->vptr)[n])(this) -动态绑定 3.动态绑定 向上转型 : 指针实现 如 B继承A B b; A a