C++ 运算符重载(二)

目录

一、自增自减运算符++,--

      (1)用成员函数的形式来进行重载
      (2)非成员函数形式的重载

二、new与delete运算符

      1、为什么要重载new与delete运算符
      2、new与delete运算符的重载
           全局new运算符做两件事:
           全局delete运算符也做两件事情:
      4、全局重载new和delete
      3、局部重载new和delete(成员函数和友元函数两种方式重载)
------------------------------------------------------------------------------------------------------------------------------------------------------

一、自增自减运算符++,--

++、--重要在既能允许前置又能允许后置,每个重载的运算符函数必须有一个明确的特征以使编译器能确定要使用的++版本。

重载前置++,--的方法与重载其他前置一元运算符一样。

重载后置++,--时,需要一个占位符作用的int型。

对于“++”和“--”这两个一元运算符,存在前置和后置的问题,在定义时必须有区分。

(1)用成员函数的形式来进行重载

++为前增量运算符时,重载函数的一般格式为:

<typeClassName ::  operator ++()

{     

       相关操作

}

++为后增量运算符时,重载函数的一般格式为:

<type>  ClassName :: operator ++(int)

{

相关操作

}

//因为是自加运算,改变后类型应该不变, 所以此处的 <tpye>应该和ClassName一样

(2)非成员函数形式的重载

以++为例说明

用友元函数来说明“++”运算符的重载时,

前置++运算符的重载一般格式为:

  friend <type>  operator ++ (ClassName &);

其中,第一个参数是要实现的++运算的对象;

 

后置++运算符的重载的一般格式为:

friend <type> operator ++(ClassName&,int);

 

其中,第一个参数是实现++运算符的对象;

而第二个参数除了用于区分是后置运算外,并没有其他意义,故起参数可有可无。

案例:

// 成员函数重载.cpp : Defines the entry point for the console application.
/*
使用成员函数来重载后置++,用友元来重载前置++
*/

#include "stdafx.h"
#include "iostream"

using namespace std;

class Clock
{
public:
	Clock(int, int, int);
	void ShowTime();
	Clock operator ++(int);				//成员函数重载后置++,后置需要辨别因子int
	friend Clock operator ++(Clock &c);		//友元函数重载前置++,
	friend ostream& operator <<(ostream& os, const Clock &c);
private:
	void IncOneSecond();
	int hour, minute, second;
};
<span style="white-space: pre;">					</span>
Clock::Clock(int h, int m, int s)<span style="white-space: pre;">			</span><span style="font-family: Arial, Helvetica, sans-serif;">//带参构造函数,初始化需要条件</span><span style="white-space: pre;">
</span>{
	if (h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60)
	{
		this->hour = h;
		this->minute = m;
		this->second = s;
	}
	else
	{
		cout << "Iint Time Error!" << endl;
	}
}

void Clock::ShowTime()
{
	cout << hour << "时" << minute << "分" << second << "秒" << endl << endl;
}

Clock Clock::operator ++(int)		
{
	Clock temp(*this);			//后置++,所以要先返回返回原本值,然后再+1,此处先把原值保存起来
	IncOneSecond();
	return temp;				//把原值返回
}

Clock operator ++(Clock &c)		<span style="white-space:pre">	</span>//前置++,先加再返回,所以把加后 的结果返回即可
{
	c.IncOneSecond();			//友元没有this指针,需要 对象名.成员 调用
	return c;
}

ostream & operator <<(ostream& os, const Clock & c)
{
	os << c.hour << "时" << c.minute << "分" << c.second << "秒" << endl << endl;
	return os;
}

void Clock::IncOneSecond()	<span style="white-space:pre">		</span>//秒钟加,也可以多做几个,分钟加,时钟加
{
	second++;
	if (second >= 60)
	{
		second = second - 60;
		minute++;
		if (minute >= 60)
		{
			minute = minute - 60;
			hour++;
			if (hour >= 24)
			{
				hour = hour % 24;
			}
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	Clock clock(23, 59, 59);
	cout << clock << endl;		<span style="white-space:pre">	</span>//当前时间


	clock++.ShowTime();			//后++,显示当前时间,但是时间已经+了
	clock.ShowTime();			//显示加后的时间

	(++clock).ShowTime();		<span style="white-space:pre">	</span>//前++,显示加后的时间

	return 0;
}

二、new与delete运算符

1、为什么要重载new与delete运算符

    对于某一个类来讲,可以通过重载该类的运算符new与delete来实现控制在何处为该类的动态对象分配空间,这样可以提高堆空间分配和归还效率。并且,这样我们可以尽量避免“碎片”问题。

 

2、new与delete运算符的重载

前面我们利用new运算符来创建动态对象时,都是使用系统提供的全局new运算符操作从程序的中分配空间的。


全局new运算符做两件事:

       A、分配指定大小的内存空间,返回一个指向该内存空间的void*指针

用来分配内存空间的函数的原型为:

void * operator new(size_t st);

st为所分配的内存空间的大小,它是编译器根据new运算符后面给定的类名,自动计算传递给operator new函数的,不需要我们去计算。

B自动调用其后指定的类的构造函数,来初始化A所有分配的内存空间,并将内存空间首地址强制转换成指定类型的指针返回。

例如:

A*p=newA;

New运算符

A步:首先调用“void* operator new(sizeof(A));”分配A类型对象占用的空间。

B步:接下来,调用A类的无参数构造函数初始化分配的内存空间,最后将地址设置成A*类型 并返回。

 

重载的new运算符只能改变第A步的工作,即通过提供不同的operator new函数,来改变分配内存的方式。

第B步是不能够修改的,即使是重载的new,也自动具有B的功能。

当动态创建的对象不再需要时,我们必须析构该对象,并释放该对象占有的内存空间。

全局delete运算符也做两件事情:

A 调用delete运算符后指针所指向的对象的构析函数;

B 释放P所指向的内存空间。

用来释放内存空间的函数的原型为:

void  delete(void *pv);

pv指向将要被释放的内存空间。

        例如:

        delete p;


delete运算符

A首先调用p所指向的对象的析构函数,

B然后调用operator delete(p);释放p指向的内存空间。

在new时,系统已经记录下了p指向的内存空间的大小。因此delete知道需要释放多少内存。

3、局部重载new和delete(可以使用成员函数和友元函数两种方式重载)

使用new分配某个重载了new的类的对象空间时,

先调用new的重载函数,再调用该类的构造函数,

如果该类的构造函数有参数要求,则必须给出对应的实参。

 

delete释放(某个重载了delete的)类的对象空间,

先调用类的构析函数,然后再调用重载的delete函数。

 

(new 先重载函数,再构造函数) (delete 先析构函数,再重载delete函数)

4、全局重载new和delete

可以在任何类说明之外重载new和delete,使它们成为全局的。

当new和delete被重载为全局时,C++原来的new与delete被忽略,并且重载的运算符用于所有类型(包括标准和用户定义类型)的分配要求。

综合应用实例:

// 成员函数重载.cpp : Defines the entry point for the console application.
/*
局部重载new,全局重载delete 
*/

#include "stdafx.h"
#include "iostream"

using namespace std;

class Clock
{
public:
	Clock(int, int, int);
	~Clock()
	{
		cout << "Clock 析构函数" << endl;
	}

	void* operator new(size_t size);<span style="white-space:pre">		</span>//局部重载new
	
	friend ostream& operator <<(ostream& os, const Clock &c);
private:
	int hour, minute, second;
};
Clock::Clock(int h, int m, int s)
{
	if (h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60)
	{
		this->hour = h;
		this->minute = m;
		this->second = s;
		cout << "Clock 构造函数" << endl;
	}
	else
	{
		cout << "Iint Time Error!" << endl;
	}
}

void* Clock::operator new(size_t size)
{
	cout << "局部 Clock new " << endl;
	return malloc(size);
}

void operator delete(void *p)			<span style="white-space:pre">	</span>//全局重载delete
{
	cout << "全局 Clock new" << endl;
	free(p);
}


ostream & operator <<(ostream& os, const Clock & c)
{
	os << c.hour << "时" << c.minute << "分" << c.second << "秒" << endl << endl;
	return os;
}



int _tmain(int argc, _TCHAR* argv[])
{
	Clock *c1 = new Clock(8, 8, 8);
	Clock *c2 = new Clock(5, 5, 5);

	if (!c1 || !c2)
	{
		cout << "动态创建失败" << endl;
		return -1;
	}

	cout << *c1 << endl;
	cout << *c2 << endl;

	delete c1;
	delete c2;

	return 0;
}


局部和全局重载 new和delete唯一区别就是在哪里声明和实现


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值