C++操作符函数重载

操作符函数重载

操作符函数

1、在C++中针对类类型的对象的运算符,由于它们肯定不支持真正的运算操作,因此编译器会将它们翻译成函数,这种就叫操作符函数(运算符函数)。
2、编译器把运算符翻译成运算符函数,可以针对自定义的类类型设计它独有的运算功能。
3、其实各种运算符已经具备一些功能,再次实现它的就叫运算符重载。

双目运算符

a+b
成员函数
	a.operator+(b);
全局函数
	operator+(a,b);

单目运算符

!a
成员函数
	a.operator!(void);
全局函数
	operator!(a);

双目操作符函数重载

成员函数

const 类 operator#(const 类& that) const
{
	return 类(参数#参数);
}
注意:双目运算符的运算结果是个右值,返回值应该加const,然后为了const对象能够调用参数应写const,函数也应该具备const属性
class Point
{
	int x;
	int y;
public:
	Point(int _x=0,int _y=0)
	{
		x = _x;
		y = _y;
	}
	const Point operator+(const Point& that) const
	{
		return Point(that.x+x,that.y+y);
	}
};

全局函数

类 operator#(const 类& a,const 类& b)
{

}
注意:全局函数不是成员函数,可能会访问到类的私有成员,解决这种问题可以把函数声明为类的友元函数(友元函数不是成员函数)。
class Point
{
	int x;
	int y;
public:
	Point(int _x=0,int _y=0)
	{
		x = _x;
		y = _y;
	}
	friend const Point operator+(const Point& a,const Point& b);
};
const Point operator+(const Point& a,const Point& b)

	return Point(a.x+b.x,a.y+b.y);
}

友元函数

1、在类的外部某个想访问类的私有成员(public/protected/private)时,需要把所在的函数声明为友元,但友元只是朋友,没有实际的拥有权,因此它只有访问权(其根本原因是它没有this指针)。
2、友元函数的声明:把函数声明写一份到类中,在声明前加上friend关键字,使用友元既可以把操作符函数定义为全局的,也可以确保类的封装性。
注意:友元函数与成员函数不会构成重载关系,因为它们不在同一个作用域中。

赋值类型的双目运算符

1、获取单参构造与赋值运算符的调用方式。

String str = "sss"; // 会调用单参构造,而不会调用赋值运算符
str = "hehe"; // 会调用赋值运算符

2、左操作数不能具有const属性

1、成员函数不能是常函数
2、全局函数的第一个参数不能有const属性
class Point
{
	int x;
	int y;
public:
	Point(int _x=0,int _y=0)
	{
		x = _x;
		y = _y;
	}
	/*
	const Point& operator+=(const Point& that)
	{
		x += that.x;
		y += that.y;
		return *this;
	} // 成员函数
	*/
	friend const Point& operator+=(Point& a,const Point& b);
};
const Point& operator+=(Point& a,const Point& b)
{
	a.x += b.y;
	a.y += b.y;
	return a;
}

单目操作符函数重载

-,~,!,&,*,->,.

成员函数

对象.operator#(void)
const 类 operator#(void)
{

}

全局函数

const 类& operator#(const 类& that)
{

}

前++/–

类& operator#(void)
{
	
}
类& operator#(类& that)
{
	
}
class Point
{
	int x;
	int y;
public:
	Point(int _x=0,int _y=0)
	{
		x = _x;
		y = _y;
	}
	/*Point& operator++(void)
	{
		++x;
		++y;
		return *this;
	} // 成员函数
	*/
	friend Point& operator++(Point& that);
};
Point& operator++(Point& that)
{
	that.x++;
	that.y++;
	return that;
}

后++/–

const 类& operator#(int)
{
	
}
const 类& operator(类& that,int)
{
	
}
class Point
{
	int x;
	int y;
public:
	Point(int _x=0,int _y=0)
	{
		x = _x;
		y = _y;
	}
	/*Point operator++(int)
	{
		Point temp(x,y);
		x++;
		y++;
		return temp;
	} // 成员函数,int为哑元
	*/
	friend Point operator++(Point& that,int);
};
Point operator++(Point& that,int)
{
	Point temp(that.x,that.y);
	that.x++;
	that.y++;
	return temp;
}

输入输出操作符重载

1、cout是ostream类型的对象,cin是istream类型的对象
2、如果输入输出运算符为成员函数,那么调用者应该是ostream/istream,而我们无权增加标准库的代码,因此输入/输出运算符只能定义为全局函数
注意:在输入输出过程中,cin/cout会记录错误标志,因此不能加const属性

ostream& operator<<(ostream& os,const 类& p)
{
	
}
istream& operator>>(istream& is,类& p)
{
	
}
class Point
{
	int x;
	int y;
public:
	Point(int _x=0,int _y=0)
	{
		x = _x;
		y = _y;
	}
	friend ostream& operator<<(ostream& os,const Point& p);
	friend istream& operator>>(istream& is,Point& p);
};
ostream& operator<<(ostream& os,const Point& p)
{
	return os << p.x << "," << p.y;
}
istream& operator>>(istream& is,Point& p)
{
	cout << "请输入x的值:";
	is >> p.x;
	cout << "请输入y的值:";
	is >> p.y;
	return is;
}

特殊操作符的重载

下标操作符[]

下标操作符常用于在容器中以下标方式获取元素。

类型& operator[](int i)

函数操作符()

一个类如果重载了函数操作符,那么它的对象就可以像函数一样使用,参数的个数及返回值类型,可以不确定,它是唯一一个可以有缺省参数的操作符

解引用操作符*、成员访问操作符->

如果一个类重载了*和->,那么它的对象就可以像指针一样使用。所谓的智能指针就是一种类对象,它支持解引用和成员访问操作符。

智能指针

常规指针的缺点:

当一个常规指针离开它的作用域时,只有该指针所占用的空间会被释放,而它指向的内存空间能否被释放就不一定了,在一些特殊情况下(人为、业务逻辑的特殊)free或delete没有执行,就会形成内存泄漏。

智能指针的优点:

智能指是一个封装了常规指针的类类型对象,当它离开作用域时,它的析构函数会负责释放常规指针所指向的动态内存(以正确方式创建的智能指针,它的析构函数才会正确执行)。

智能指针和常规指针的相同点:

都支持*和->运算

不同点:

任何时候,一个对象只能使用一个智能指针来指向,而常规指针可以指向多次。
智能指针的赋值操作需要经过拷贝构造和赋值构造特殊处理(深拷贝)。
class Int
{
	int val;
public:
	Int(int val=0):val(val){}
	Int& operator=(const int val)
	{
		this->val = val;
		return *this;
	}
	~Int(void)
	{
		cout << "Int的析构函数" << endl;
	}
	friend ostream& operator<<(ostream& os,Int& n);
};
ostream& operator<<(ostream& os,Int& n)
{
	return os << n.val;
}
class IntPointer
{
	Int* ptr;
public:
	IntPointer(Int* ptr):ptr(ptr){}
	Int& operator*(void)
	{
		return *ptr;
	}
	~IntPointer(void)
	{
		delete ptr;
	}
};
int main()
{
	Int* num = new Int(100);
	IntPointer p = num;
	cout << *p << endl;
	*p = 20;
	cout << *p << endl;
}

new/delete/new[]/delete[]运算符重载

1、C++中缺省的堆内存管理器速度较慢,重载new和delete底层使用malloc/free可以提高运行速度。
2、new在失败时会发生异常,而每次使用new时为了安全都应该进行异常捕获,而重载new操作符只需要在操作符函数中进行一次错误处理即可。
3、一些占字节数比较小的类,频繁使用new,可能会产生大量的内存碎片,而重载new操作符后,可以适当的扩大申请的字节数,减少内存碎片产生的机率。
4、重载new/delete 可以记录堆内存使用的信息
5、重载delete可以检测到释放内存失败时的信息,检测到内存泄漏。

class Test
{
	void* ptr;
public:
	Test(const int val){}
	Test(void)
	{
		cout << "构造函数" << endl;
	}
	~Test(void)
	{
		cout << "析构函数" << endl;
	}
	static void* operator new(size_t size)
	{
		printf("创建堆内存%d字节\n",size);
		malloc(size);
	}
	static void operator delete(void* ptr)
	{
		cout << "释放内存" << endl;
		free(ptr);
	}
};
int main()
{
	Test* p1 = new Test;
	p1 = NULL;
	delete p1;
}

重载运算符的限制

1、不能重载的操作符

域限定符 ::
直接成员访问操作符 .
三目运算符 ?:
字节长度操作符 sizeof
类型信息操作符 typeid

2、重载操作符不能修改操作符的优先级
3、无法重载所有基本类型的操作符运算
4、不能修改操作符的参数个数操作数
5、不能发明新的操作符

关于操作符重载的建议

1、在重载操作符时,要根据操作符实际的功能和意义来确定具体参数、返回值、是否具有const属性,返回值是否是引用或者是临时对象。
2、重载操作符要合情合理(有意义),要以实际用途为前提。
3、重载操作符的意义是为了让对象的操作更简单、方便,提高代码的可读性。
4、重载操作符要与默认的操作符的功能、运算规则一致,不要出现反人类的操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值