从零开始学C++之运算符重载(四):类型转换运算符、*运算符重载、->运算符重载、operator new 和 operator delete

一、类型转换运算符

必须是成员函数,不能是友元函数 没有参数 不能指定返回类型 函数原型:operator 类型名();

#ifndef _INTEGER_H_
#define _INTEGER_H_

class Integer
{
public:
    Integer(int n);
    ~Integer();

    Integer &operator++();
    //friend Integer& operator++(Integer& i);

    Integer operator++(int n);
    //friend Integer operator++(Integer& i, int n);

    operator int();

    void Display() const;
private:
    int n_;
};

#endif // _INTEGER_H_
#include "Integer.h"
#include <iostream>
using namespace std;

Integer::Integer(int n) : n_(n)
{
}

Integer::~Integer()
{
}

Integer &Integer::operator ++()
{
    //cout<<"Integer& Integer::operator ++()"<<endl;
    ++n_;
    return *this;
}

//Integer& operator++(Integer& i)
//{
//  //cout<<"Integer& operator++(Integer& i)"<<endl;
//  ++i.n_;
//  return i;
//}

Integer Integer::operator++(int n)
{
    //cout<<"Integer& Integer::operator ++()"<<endl;
    //n_++;
    Integer tmp(n_);
    n_++;
    return tmp;
}

//Integer operator++(Integer& i, int n)
//{
//  Integer tmp(i.n_);
//  i.n_++;
//  return tmp;
//}

Integer::operator int()
{
    return n_;
}

void Integer::Display() const
{
    cout << n_ << endl;
}
#include "Integer.h"
#include <iostream>
using namespace std;

int add(int a, int b)
{
    return a + b;
}

int main(void)
{
    Integer n(100);
    n = 200;
    n.Display();

    int sum = add(n, 100);

    cout << sum << endl;

    int x = n;
    int y = static_cast<int>(n);

    return 0;
}

其中n = 200; 是隐式将int 转换成Interger类;int x = n; 是调用operator int 将Interger 类转换成int,也可以使用static_cast 办到;此外add 函数传参时也会调用operator int 进行转换。

二、->运算符重载

类* operator->();

类& operator*();

#include <iostream>
using namespace std;

class DBHelper
{
public:
    DBHelper()
    {
        cout << "DB ..." << endl;
    }
    ~DBHelper()
    {
        cout << "~DB ..." << endl;
    }

    void Open()
    {
        cout << "Open ..." << endl;
    }

    void Close()
    {
        cout << "Close ..." << endl;
    }

    void Query()
    {
        cout << "Query ..." << endl;
    }
};

class DB
{
public:
    DB()
    {
        db_ = new DBHelper;
    }

    ~DB()
    {
        delete db_;
    }

    DBHelper *operator->()
    {
        return db_;
    }

    DBHelper &operator*()
    {
        return *db_;
    }
private:
    DBHelper *db_;
};


int main(void)
{
    DB db;
    db->Open();
    db->Query();
    db->Close();

    (*db).Open();
    (*db).Query();
    (*db).Close();

    return 0;
}

db->Open(); 等价于 (db.operator->())->Open(); 会调用operator-> 返回DBHelper类的指针,调用DBHelper的成员函数Open()。这样使用的好处是不需要知道db 对象什么时候需要释放,当生存期结束时,会调用DB类的析构函数,里面delete db_; 故也会调用DBHelper类的析构函数。

(*db).Open(); 等价于(db.operator*()).Open();

三、operator new 和 operator delete

前面曾经提过:实际上new 有三种用法,包括operator new、new operator、placement new,new operator 包含operator new,而placement new 则没有内存分配而是直接调用构造函数。下面看例子:

#include <iostream>
using namespace std;

class Test
{
public:
    Test(int n) : n_(n)
    {
        cout << "Test(int n) : n_(n)" << endl;
    }
    Test(const Test &other)
    {
        cout << "Test(const Test& other)" << endl;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
    /****************************************************************/
    void *operator new(size_t size)
    {
        cout << "void* operator new(size_t size)" << endl;
        void *p = malloc(size);
        return p;
    }

    void operator delete(void *p) //与下面的operator delete函数类似,共存的话优先;
    {
        //匹配上面的operator new 函数
        cout << "void operator delete(void* p)" << endl;
        free(p);
    }

    void operator delete(void *p, size_t size)
    {
        cout << "void operator delete(void* p, size_t size)" << endl;
        free(p);
    }
    /**********************************************************************/

    void *operator new(size_t size, const char *file, long line)
    {
        cout << "   void* operator new(size_t size, const char* file, long line);" << endl;
        cout << file << ":" << line << endl;
        void *p = malloc(size);
        return p;
    }

    void operator delete(void *p, const char *file, long line)
    {
        cout << "   void operator delete(void* p, const char* file, long line);" << endl;
        cout << file << ":" << line << endl;
        free(p);
    }

    void operator delete(void *p, size_t size, const char *file, long line)
    {
        cout << "void operator delete(void* p, size_t size, const char* file, long line);" << endl;
        cout << file << ":" << line << endl;
        free(p);
    }
    /**************************************************************************/
    void *operator new(size_t size, void *p)
    {
        cout << "void* operator new(size_t size, void* p);" << endl;
        return p;
    }

    void operator delete(void *, void *)
    {
        cout << "void operator delete(void *, void *);" << endl;
    }
    /**************************************************************************/
    int n_;
};

/*************** global **********************************************/

void *operator new(size_t size)
{
    cout << "global void* operator new(size_t size)" << endl;
    void *p = malloc(size);
    return p;
}

void operator delete(void *p)
{
    cout << "global void operator delete(void* p)" << endl;
    free(p);
}
/**********************************************************************/

void *operator new[](size_t size)
{
    cout << "global void* operator new[](size_t size)" << endl;
    void *p = malloc(size);
    return p;
}

void operator delete[](void *p)
{
    cout << "global void operator delete[](void* p)" << endl;
    free(p);
}
/***********************************************************************/

int main(void)
{
    Test *p1 = new Test(100);   // new operator = operator new + 构造函数的调用
    delete p1;

    char *str1 = new char;
    delete str1;

    char *str2 = new char[100];
    delete[] str2;

    char chunk[10];


    Test *p2 = new (chunk) Test(200);   //operator new(size_t, void *_Where)
    // placement new,不分配内存 + 构造函数的调用
    cout << p2->n_ << endl;
    p2->~Test();                        // 显式调用析构函数

    //Test* p3 = (Test*)chunk;
    Test *p3 = reinterpret_cast<Test *>(chunk);
    cout << p3->n_ << endl;



#define new new(__FILE__, __LINE__)
    //Test* p4 = new(__FILE__, __LINE__) Test(300);
    Test *p4 = new Test(300);
    delete p4;

    return 0;
}

从输出可以看出几点:

1、new operator 是分配内存(调用operator new) + 调用构造函数

2、operator new 是只分配内存,不调用构造函数

3、placement new 是不分配内存(调用operator new(与2是不同的函数) 返回已分配的内存地址),调用构造函数

4、delete 是先调用析构函数,再调用operator delete.

5、如果new 的是数组,对应地也需要delete [] 释放

注意:

1、如果存在继承或者对象成员,那么调用构造函数或者析构函数时将有多个,按一定顺序调用,参见这里

2、假设存在继承,delete 基类指针;涉及到虚析构函数的问题,参见这里

最后还存在一点疑问的是 delete p4 为什么调用的不是 void operator delete(void* p, const char* file, long line); 而是

void operator delete(void* p) ; 希望有明白的朋友告诉我一声。

参考:

C++ primer 第四版 Effective C++ 3rd C++编程规范

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

Kotlin 扩展函数与属性 实例代码

771
来自专栏大数据钻研

你不知道的 Javascript

作用域 词法作用域:编译阶段确定(欺骗词法作用域 eval with) JavaScript 1 2 3 4 5 6function foo(str){ "u...

2634
来自专栏Google Dart

Dart 中构造函数定义与使用详解 原

在这种没有构造函数的情况下Dart会为其隐式定义一个默认构造函数(与类名相同、无参数)

982
来自专栏IT技术精选文摘

阿里架构师带你深入浅出jvm

1782
来自专栏Golang语言社区

package reflect

reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函...

983
来自专栏机器学习入门

POJ 刷题系列:2632. Crashing Robots

题意: 在一张地图(A x B)中给出N个robot的位置和初始移动方向,以及M条指令,任意两个robot不能同时移动,问是否存在非法的crash状态(撞墙,...

1958
来自专栏Golang语言社区

Golang面试题

最近在很多地方看到了golang的面试题,看到了很多人对Golang的面试题心存恐惧,也是为了复习基础,我把解题的过程总结下来。 面试题 写出下面代码输出内容。...

6149
来自专栏Java编程

Java习惯用法总结

在Java编程中,有些知识 并不能仅通过语言规范或者标准API文档就能学到的。在本文中,我会尽量收集一些最常用的习惯用法,特别是很难猜到的用法。(Joshua ...

1K3
来自专栏代码拾遗

反射基础之Method

一个方法声明包括:方法名,描述符,参数,返回类型和异常。可以通过java.lang.reflect.Method类获取这些信息。 下面的例子说明了如何获取一个类...

823
来自专栏hbbliyong

使用委托实现同步回调与异步回调

使用委托可以执行的一项有用操作是实现回调。回调是传入函数的方法,在函数结束执行时调用该方法。 例如,有一个执行一系列数学操作的函数。在调用该函数时,也向其...

3456

扫码关注云+社区