我是靠谱客的博主 安详砖头,最近开发中收集的这篇文章主要介绍(P25)运算符重载:类型转换运算符 ,->运算符 ,operator new、operator delete,new运算符的3种用法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • 1.类型转换运算符
    • 2.->运算符
    • 3.operator new、operator delete,new运算符的3种用法

1.类型转换运算符

  • 必须是成员函数,不能是友元函数
  • 没有参数(操作数是什么?)
    因为操作数就是类对象自身
  • 不能指定返回类型(其实已经指定了)
    它要指定的类型就是返回类型
  • 函数原型:
operator 类型名();
  • eg:25cpp25cpp25cpp1.cpp
#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;//通过转换构造函数Integer(int n);也叫构造函数,可以将200转换为类类型,赋值给n
	n.Display();

	int sum = add(n, 100);

	cout<<sum<<endl;

	int x = n;//隐式转换:调用类型转换运算符operator int();
	int y = static_cast<int>(n);//显示转换,调用类型转换运算符operator int();

	return 0;
}
  • 类声明及定义
    25cpp25cpp25cppInteger.h
#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();//没有参数,就是将自身转换为int型

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

#endif // _INTEGER_H_

25cpp25cpp25cppInteger.cpp

#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;
}
  • 测试:
    在这里插入图片描述

2.->运算符

  • eg:25cpp25cpp25cpp2.cpp
#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()
	{
		//构造一个DBHelper对象
		db_ = new DBHelper;
	}

	~DB()
	{
		delete db_;
	}

	//重载指针运算符->
	//指针运算符重载返回一个内部的指针,然后通过内部的指针访问DBHelper的成员函数
	DBHelper* operator->()
	{
		return db_;
	}
private:
	DBHelper* db_;//DBHelper对象,函数指针是db_
};


int main(void)
{
	//利用类对象db确定析构机制,将它所包装的动态对象销毁掉
	DB db;
	db->Open();
	db->Query();
	db->Close();


	return 0;
}
  • 测试:
    指针运算符重载

在这里插入图片描述

3.operator new、operator delete,new运算符的3种用法

  • (1)operator new与之对应的delete操作是:
void* operator new(size_t size)

void operator delete(void* p)
New运算符重载,delete运算符也要被重载
void operator delete(void* p, size_t size)void operator delete(void* p)可以共存,先调用void operator delete(void* p)
  • (2)这个operator new与之对应的delete操作是:
void* operator new(size_t size, const char* file, long line)

void operator delete(void* p, const char* file, long line)
void operator delete(void* p, size_t size, const char* file, long line)
两者是等价的,都出现时,上面的delete优先
  • (3)针对数组而言,这个operator new与之对应的delete操作是:
void* operator new[](size_t size)

void operator delete[](void* p)
void operator delete[](void* p, size_t size)
  • new有3种用法
    (1)new operator:不能被重载
    (2)operator new:可以被重载
    (3)placement new
    placement new是在已经申请的内存上构建对象. 这就是我们调用new的时候会调用对象的构造函数的原因。

  • eg:25cpp25cpp25cpp3.cpp

#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)
	{
		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<<file<<":"<<line<<endl;
		void* p = malloc(size);
		return p;
	}

	void operator delete(void* p, const char* file, long line)
	{
		//打印哪一个文件,哪一行
		cout<<file<<":"<<line<<endl;
		free(p);
	}

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

	//placement new的用法如下:
	//这是局部的 placement new,已经存在的内存地址,直接返回就可以了,内部不需要分配空间
	//所以相应的delete不需要做任何的操作
	void* operator new(size_t size, void* p)
	{
		return p;
	}

	void operator delete(void *, void *)
	{
	}

	int n_;
};

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)
{
	//new operator用法
	Test* p1 = new Test(100);	// 称作是:new operator,new operator = operator new内存分配 + 构造函数的调用
	delete p1;

	//这个是全局的operator new操作
	char* str = new char[100];
	delete[] str;

	char chunk[10];

	//placement new用法
	//在chunk这块内存上进行new操作
	//返回的是p2指针就等于chunk的地址
	//p2的地址就等于chunk地址,4个字节的Test对象使用的空间就是chunk空间的4个字节
	Test* p2 = new (chunk) Test(200);	//operator new(size_t, void *_Where)
										// placement new,不分配内存 + 构造函数的调用
	cout<<p2->n_<<endl;
	p2->~Test();						// 显式调用析构函数,析构函数可以被显式调用的
										//不能使用delete p2,因为它不是堆上生成的内存,它的内存在已经存在的chunk内存中
										//所以要使用显式调用析构函数的方式来调用

	//强制转换
	//Test* p3 = (Test*)chunk;等价于下面的类型转换
	Test* p3 = reinterpret_cast<Test*>(chunk);
	cout<<p3->n_<<endl;



	//Test* p4 = new(__FILE__, __LINE__) Test(300);//传递的是operator new+构造函数的调用,operator不仅
													//传递了对象的大小300,还传递了__FILE__, __LINE__
	//delete(__FILE__, __LINE__) p4;delete p4(__FILE__, __LINE__);都没有调用与上面想对应的delete函数,后期有空可以研究下

//__FILE__表示这行所在的文件
//__LINE__表示这行所在的行号
#define new new(__FILE__, __LINE__)
	Test* p4 = new Test(300);
	delete p4;

	return 0;
}
  • 测试1:
Test* p1 = new Test(100);	// 称作是:new operator,new operator = operator new内存分配 + 构造函数的调用

利用VS2008,跟踪一下,按下F9,
在这里插入图片描述
按下F11,调用operator new,传递了一个大小进来,当前类的大小是4个字节
在这里插入图片描述
按下shift F11可以跳出这个函数,或者按下F10不去跟踪这一行函数
在这里插入图片描述
在这里插入图片描述

  • 测试2:
	char chunk[10];
	//placement new用法
	//在chunk这块内存上进行new操作
	//返回的是p2指针就等于chunk的地址
	//p2的地址就等于chunk地址,4个字节的Test对象使用的空间就是chunk空间的4个字节
	Test* p2 = new (chunk) Test(200);	//operator new(size_t, void *_Where)
										// placement new,不分配内存 + 构造函数的调用
	cout<<p2->n_<<endl;
	//强制转换
	//Test* p3 = (Test*)chunk;
	Test* p3 = reinterpret_cast<Test*>(chunk);
	cout<<p3->n_<<endl;

在这里插入图片描述
F11,直接返回Where指针,Where的地址就是chunk的地址
在这里插入图片描述
再次按下F10
在这里插入图片描述
返回了一个存在的指针,构造的对象放在了chunk地址里面了
chunk地址与p2地址是一样的
在这里插入图片描述

在这里插入图片描述

  • 测试3:测试的上面的(1)operate new的用法

在这里插入图片描述

  • 测试4:
	//这个是全局的operator new操作
	char* str = new char[100];
	delete[] str;

重载的是带数组的operator newvoid* operator new[](size_t size)

在这里插入图片描述

  • 测试5:测试的是上面(2)operate new的用法
	void* operator new(size_t size)
	{
		cout<<"void* operator new(size_t size)"<<endl;
		void* p = malloc(size);
		return p;
	}
。。。。
。。。。
。。。。
	void operator delete(void *, void *)
	{
	}
将上述重载的newdelete的运算符全都屏蔽掉,进入debug,看到了应该与operator new相匹配的operator delete的原型

在这里插入图片描述

在这里插入图片描述

	//Test* p4 = new(__FILE__, __LINE__) Test(300);//传递的是operator new+构造函数的调用,operator不仅
													//传递了对象的大小300,还传递了__FILE__, __LINE__
	//delete(__FILE__, __LINE__) p4;delete p4(__FILE__, __LINE__);都没有调用与上面想对应的delete函数,后期有空可以研究下

//__FILE__表示这行所在的文件
//__LINE__表示这行所在的行号
#define new new(__FILE__, __LINE__)
	Test* p4 = new Test(300);
	delete p4;

在这里插入图片描述

  • 参考:new实现

最后

以上就是安详砖头为你收集整理的(P25)运算符重载:类型转换运算符 ,->运算符 ,operator new、operator delete,new运算符的3种用法的全部内容,希望文章能够帮你解决(P25)运算符重载:类型转换运算符 ,->运算符 ,operator new、operator delete,new运算符的3种用法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部