【菜鸟C++学习笔记】26.运算符重载

在面向对象的语言中,如果想对对象进行加、减、赋值等操作,用普通的运算符就会报错,当然可以定义相应用来实现这些功能的函数,但是在类中定义很麻烦,因此提出了运算符重载的概念。在C++中,使用关键词operator来定义,定义方式如下:

返回值 operator运算符 () {实现;}

注意:C++不允许重载内置运算符的含义,包括指针类型,因此返回值如果是int就会报错!

1、前置自加运算符重载

参见下面的程序:用于实现前置运算符的自加,把对象成员数值加1,并返回一个指向当前对象的指针,用于将返回的对象赋给一个新的对象。

#include <iostream>
using namespace std;
class A
{
public:
	A(){n=1;cout<<"构造函数执行"<<endl;}
	A(const A&s){n=s.n;cout<<"复制构造函数执行"<<endl;}
	~A(){cout<<"析构函数执行"<<endl;}
	int get() const {return n;}
	void set(int x){n=x;}
	void add(){n++;}
	A operator++(){++n;return *this;}
private:
	int n;
};
int main()
{
	A a;
	cout<<"初始化对象a的成员值:"<<a.get()<<endl;
	a.add();
	cout<<"执行add()对象a的成员值:"<<a.get()<<endl;
	A b=++a;//自加运算符重载后,执行调用重载后的函数,即第10行定义的函数
	cout<<"执行前置自加运算后对象a的成员值:"<<a.get()<<endl;
	cout<<"新建对象b的成员值:"<<b.get()<<endl;
	return 0;
}
运行结果:


分析:

1)main函数第一行,创建对象a,执行构造函数并初始化成员n的值为1

2)在类中定义了一个add函数,用于对成员变量进行操作,执行后的作用是使对象a的数据成员n加1

3)执行A b=++a时,调用运算符重载函数,并返回指向当前对象的指针*this,传递给新的对象,对象传递过程中需调用复制构造函数,而重载运算符的函数作用也是让对象的值自加,由输出结果可见。

4)由于整个程序创建了两个对象,因此调用两次析构函数析构对象。

讨论:

如果把第22行改为a=++a,则不会调用复制构造函数,因为没有创建新对象!


2、重载后置自加运算符

后置自加与前置自加的区别是后置自加会先返回值,再加1,而前置自加是先加1再返回。因此在重载后置自加运算符时,先创建一个临时对象,把当前对象的值赋给这个临时对象,再把当前对象的数据自加,之后按值返回临时对象。注意必须按值返回,否则临时对象超出作用域会被析构掉!

我们和上一个程序写在一起,为了避免重复,在这个后置自加重载函数后加一个无用的参数,程序参考如下:

#include <iostream>
using namespace std;
class A
{
public:
	A(){n=1;cout<<"构造函数执行"<<endl;}
	A(const A&s){n=s.n;cout<<"复制构造函数执行"<<endl;}
	~A(){cout<<"析构函数执行"<<endl;}
	int get() const {return n;}
	void set(int x){n=x;}
	void add(){n++;}
	A operator++(){++n;return *this;}
	A operator++(int o){A temp(*this);++n;return temp;}
private:
	int n;
};
int main()
{
	A a;
	cout<<"初始化对象a的成员值:"<<a.get()<<endl;
	a.add();
	cout<<"执行add()对象a的成员值:"<<a.get()<<endl;
	A b=++a;//自加运算符重载后,执行调用重载后的函数,即第10行定义的函数
	cout<<"执行前置自加运算后对象a的成员值:"<<a.get()<<endl;
	cout<<"新建对象b的成员值:"<<b.get()<<endl;
	A c=a++;//自加运算符重载后,执行调用重载后的函数,即第10行定义的函数
	cout<<"执行后置自加运算后对象a的成员值:"<<a.get()<<endl;
	cout<<"新建对象c的成员值:"<<c.get()<<endl;
	return 0;
}

输出结果:

分析:

第26行调用重载后的后置自加运算符时,先构造一个临时对象,把n=3时的对象a赋给这个临时对象,之后把a中的n加1,再把临时对象返回,并把这个返回的对象副本赋给新对象c,由于这个临时对象中n的值并没有自加,因此c的成员值输出为3;

 

3、重载加法运算符

重载方法:把“+”后的对象作为参数传递进来与源对象的值相加,并利用构造函数返回一个对象赋给一个新的对象。程序如下:

#include <iostream>
using namespace std;
class A
{
public:
	A(){}
	A(int i){n=i;}
	int get() const {return n;}
	void set(int x){n=x;}
	const A operator+(const A&c){return A(n+c.get());}
private:
	int n;
};
int main()
{
	A a(1),b(2),c;
	c=a+b;
	cout<<"a:"<<a.get()<<endl;
	cout<<"b:"<<b.get()<<endl;
	cout<<"c:"<<c.get()<<endl;
	return 0;
}
输出结果:



4、重载赋值运算符

赋值运算符与加法运算符重载方式类似,将“=”后的对象传递给=函数中,把数据成员的值赋给临时对象,之后返回一个指向当前对象的指针赋给新的对象。

#include <iostream>
using namespace std;
class A
{
public:
	A(){}
	A(int i){n=i;}
	int get() const {return n;}
	void set(int x){n=x;}
	A operator=(A&c){n=c.get();return *this;}
private:
	int n;
};
int main()
{
	A a(1),c;
	c=a;
	cout<<"a:"<<a.get()<<endl;
	cout<<"c:"<<c.get()<<endl;
	return 0;
}
输出结果:


讨论:

这样重载方式属于浅层复制,按值传递是没问题的,如果类A的成员变量改为指针,就会出现两个指针指向同一块内存区域的问题,删除一个会导致另一个称为迷途指针,解决方法是实用深层复制的方法,即分别为传递进来的对像指针开辟一块内存区域,也把要赋给的对象的指针保存在另一区域中,如下面的程序:

#include <iostream>
using namespace std;
class A
{
public:
	A(){n=new int;cout<<"不带参数的构造函数"<<endl;}
	A(int i){n=new int;*n=i;cout<<"带一个参数的构造函数"<<endl;}
	~A(){delete n;n=0;cout<<"析构函数调用"<<endl;}
	int get() const {return *n;}
	void set(int x){*n=x;}
	const A &equal(const A&c){*n=c.get();return *this;}
	const A &operator=(const A&c){*n=c.get();return *this;}
private:
	int *n;
};
int main()
{
	A *a=new A(1);
	A b;
	b=*a;
	cout<<"a:"<<a->get()<<endl;
	cout<<"b:"<<b.get()<<endl;
	delete a;
	cout<<"b:"<<b.get()<<endl;
	return 0;
}
输出结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值