C++ Primer Plus学习笔记之运算符重载

C++ Primer Plus学习笔记之运算符重载

1,成员函数和友元函数选择的建议
下面我们先看两个例子:
成员函数重载
#include<iostream>

using namespace std;

class Complex
{
	public:
		Complex(double r=0,double i=0)
		{
			re=r;
			im=i;
		}
		Complex operator+(const Complex& obj);
		Complex operator!();
		void Display();
	private:
		double re;
		double im;
};

Complex Complex::operator+(const Complex& obj)
{
	Complex temp;
	temp.re=re+obj.re;
	temp.im=im+obj.im;
	return temp;
}

Complex Complex::operator!()
{
	Complex temp;
	temp.re=re;
	temp.im=-im;
	return temp;
}

void Complex::Display()
{
	cout<<re;
	if(im>0)
		cout<<"+"<<im<<"i"<<endl;
	else
		cout<<im<<"i"<<endl;
}

int main(int argc,char *argv[])
{
	Complex obj1(1,2),obj2(3,4);
	Complex obj3=obj1+!obj2;
	obj3.Display();

	obj3=obj1+27;
	obj3.Display();

	//obj3=27+obj1;
	//obj3.Display(); 错误,27不是Complex的对象

	return 0;
}
友元函数重载
#include<iostream>

using namespace std;

class Complex
{
	public:
		Complex(double r=0,double i=0)
		{
			re=r;
			im=i;
		}
		friend Complex operator+(const Complex& obj1,const Complex& obj2);
		Complex operator!();
		void Display();
	private:
		double re;
		double im;
};

Complex operator+(const Complex& obj1,const Complex& obj2)
{
	Complex temp;
	temp.re=obj1.re+obj2.re;
	temp.im=obj1.im+obj2.im;
	return temp;
}

Complex Complex::operator!()
{
	Complex temp;
	temp.re=re;
	temp.im=-im;
	return temp;
}

void Complex::Display()
{
	cout<<re;
	if(im>0)
		cout<<"+"<<im<<"i"<<endl;
	else
		cout<<im<<"i"<<endl;
}

int main(int argc,char *argv[])
{
	Complex obj1(1,2),obj2(3,4);
	Complex obj3=obj1+!obj2;
	obj3.Display();

	obj3=obj1+27;
	obj3.Display();

	obj3=27+obj1;
	obj3.Display();

	return 0;
}
对于成员函数重载,由于obj3=27+obj1的显示调用为obj3=27.operator+(obj1),而27不是Complex类型,因此编译器不能调用Complex的operator+()重载运算符完成加法操作;
对于友元函数重载,由于obj3=27+obj1的调用通过有一个参数缺省的构造函数Complex(double r=0,double i=0),系统可以自动将27转换为Complex(27)对象,因此编译通过;
由此可知,成员函数仅仅能为一个实际对象所调用,友元无此限制。因此若运算符的操作需要修改类对象的状态,则它应该是成员函数,而不应该是友元。相反,如果运算符的操作数(尤其是第一个操作数)希望有隐式类型转换,则该运算符重载必须用友元函数,而不是成员函数。
2,重载++的前缀和后缀
成员函数重载
#include<iostream>

using namespace std;

class Complex
{
	public:
		Complex(double r=0,double i=0)
		{
			re=r;
			im=i;
		}
		friend Complex operator+(const Complex& obj1,const Complex& obj2);
		Complex& operator++();//前缀方式
		Complex operator++(int);//后缀方式
		Complex operator!();
		void Display();
	private:
		double re;
		double im;
};

Complex operator+(const Complex& obj1,const Complex& obj2)
{
	Complex temp;
	temp.re=obj1.re+obj2.re;
	temp.im=obj1.im+obj2.im;
	return temp;
}

Complex& Complex::operator++()
{
	re++;
	im++;
	return *this;
}

Complex Complex::operator++(int)//int为占位符
{
	Complex temp(*this);//拷贝构造函数
	re++;
	im++;
	return temp;
}

Complex Complex::operator!()
{
	Complex temp;
	temp.re=re;
	temp.im=-im;
	return temp;
}

void Complex::Display()
{
	cout<<re;
	if(im>0)
		cout<<"+"<<im<<"i"<<endl;
	else
		cout<<im<<"i"<<endl;
}

int main(int argc,char *argv[])
{
	Complex obj1(1,2),obj2;
	cout<<"First obj1=";
	obj1.Display();

	obj2=obj1++;
	cout<<"Second obj1=";
	obj1.Display();
	cout<<"and obj2=";
	obj2.Display();

	obj2=++obj1;
	cout<<"Third obj1=";
	obj1.Display();
	cout<<"and obj2=";
	obj2.Display();

	return 0;
}
友元函数重载
#include<iostream>

using namespace std;

class Complex
{
	public:
		Complex(double r=0,double i=0)
		{
			re=r;
			im=i;
		}
		friend Complex operator+(const Complex& obj1,const Complex& obj2);
		friend Complex& operator++(Complex& obj);//前缀方式
		friend Complex operator++(Complex& obj,int);//后缀方式
		Complex operator!();
		void Display();
	private:
		double re;
		double im;
};

Complex operator+(const Complex& obj1,const Complex& obj2)
{
	Complex temp;
	temp.re=obj1.re+obj2.re;
	temp.im=obj1.im+obj2.im;
	return temp;
}

Complex& operator++(Complex& obj)
{
	obj.re++;
	obj.im++;
	return obj;
}

Complex operator++(Complex& obj,int)//int为占位符
{
	Complex temp(obj);//拷贝构造函数
	obj.re++;
	obj.im++;
	return temp;
}

Complex Complex::operator!()
{
	Complex temp;
	temp.re=re;
	temp.im=-im;
	return temp;
}

void Complex::Display()
{
	cout<<re;
	if(im>0)
		cout<<"+"<<im<<"i"<<endl;
	else
		cout<<im<<"i"<<endl;
}

int main(int argc,char *argv[])
{
	Complex obj1(1,2),obj2;
	cout<<"First obj1=";
	obj1.Display();

	obj2=obj1++;
	cout<<"Second obj1=";
	obj1.Display();
	cout<<"and obj2=";
	obj2.Display();

	obj2=++obj1;
	cout<<"Third obj1=";
	obj1.Display();
	cout<<"and obj2=";
	obj2.Display();

	return 0;
}
由于++运算符修改类对象本身,因此在友元调用方式中,为了能够修改传递进函数的参数,以对象引用的方式传递。++的前缀方式返回类型为类对象的引用,后缀方式返回类型是类对象,是因为前缀方式返回的是变化之后的类对象,该类对象是作为对象引用传递进函数的,在函数调用结束之后不会被销毁;而后缀方式,函数的返回值是参数对象被修改之前的值(放到局部对象中暂时存储),因此返回的是局部对象的值,而局部对象在函数返回的时候会被销毁,因此函数的返回值只能将局部对象的值拷贝过来,而不能直接使用局部对象空间。故后缀方式返回类型为类对象,而不能是类对象的引用。
3,重载赋值运算符
#include<iostream>
#include<cstring>
#include<cassert>

using namespace std;

class String
{
	public:
		String()
		{
			msize=0;
			mstr=NULL;
		}
		String(char *str);
		String(const String& str);
		String operator+(const String& str);
		String& operator=(const String& str);
		void Display();
	private:
		char *mstr;
		int msize;
};

String::String(char *str)
{
	if(str==NULL)
	{
		msize=0;
		mstr=NULL;
	}
	else
	{
		msize=strlen(str);
		mstr=new char[msize+1];
		assert(mstr);
		strcpy(mstr,str);
	}
}

String::String(const String& str)
{
	if(str.msize==0)
	{
		msize=0;
		mstr=NULL;
	}
	else
	{
		msize=str.msize;
		mstr=new char[msize+1];
		assert(mstr);
		strcpy(mstr,str.mstr);
	}
}

String String::operator+(const String& str)
{
	String temp;
	temp.msize=msize+str.msize-1;
	temp.mstr=new char[temp.msize];
	assert(temp.mstr);
	strcpy(temp.mstr,mstr);
	strcpy(&(temp.mstr[msize]),str.mstr);
	return temp;
}

String& String::operator=(const String& str)
{
	if(this==&str)
		return *this;
	if(msize>0)
		delete []mstr;
	msize=str.msize;
	mstr=new char[msize];
	assert(mstr);
	strcpy(mstr,str.mstr);
	return *this;
}

void String::Display()
{
	cout<<mstr<<endl;
}

int main(int argc,char *argv[])
{
	char str1[]={"Hello"};
	char str2[]={"World"};
	String s1(str1),s2(str2),s3;
	s3=s1+s2;
	s3.Display();

	return 0;
}
如果用户没有定义一个类重载赋值运算符,编译器将生成一个缺省的赋值运算符。赋值运算符把源对象逐域地拷贝到目的对象;
下面做一个总结,编译器会自动生成的函数有:
1,构造函数;
2,析构函数;
3,拷贝构造函数;
4,赋值运算符;
拷贝构造函数和赋值运算符的区别是:
拷贝构造函数是要创建一个新的对象,而赋值运算符则是改变一个已经存在的对象的值;
需要注意的是当一个类包含指针类型的数据成员时,最好进行赋值运算符和拷贝构造函数的重载,否则很有可能造成指针悬挂问题(动态申请的空间无法访问,无法释放);
4,重载[]运算符
#include<iostream>
#include<cstring>
#include<cassert>

using namespace std;

class String
{
	public:
		String()
		{
			msize=0;
			mstr=NULL;
		}
		String(char *str);
		String(const String& str);
		String operator+(const String& str);
		String& operator=(const String& str);
		char& operator[](int index);//可读可写
		char operator[](int index)const;//只读
		void Display();
	private:
		char *mstr;
		int msize;
};

String::String(char *str)
{
	if(str==NULL)
	{
		msize=0;
		mstr=NULL;
	}
	else
	{
		msize=strlen(str);
		mstr=new char[msize+1];
		assert(mstr);
		strcpy(mstr,str);
	}
}

String::String(const String& str)
{
	if(str.msize==0)
	{
		msize=0;
		mstr=NULL;
	}
	else
	{
		msize=str.msize;
		mstr=new char[msize+1];
		assert(mstr);
		strcpy(mstr,str.mstr);
	}
}

String String::operator+(const String& str)
{
	String temp;
	temp.msize=msize+str.msize-1;
	temp.mstr=new char[temp.msize];
	assert(temp.mstr);
	strcpy(temp.mstr,mstr);
	strcpy(&(temp.mstr[msize]),str.mstr);
	return temp;
}

String& String::operator=(const String& str)
{
	if(this==&str)
		return *this;
	if(msize>0)
		delete []mstr;
	msize=str.msize;
	mstr=new char[msize];
	assert(mstr);
	strcpy(mstr,str.mstr);
	return *this;
}

char& String::operator[](int index)//可读可写
{
	return mstr[index-1];
}

char String::operator[](int index)const//只读,但只能由常对象调用
{
	return mstr[index-1];
}

void String::Display()
{
	cout<<mstr<<endl;
}

int main(int argc,char *argv[])
{
	char str1[]={"Hello"};
	char str2[]={"World"};
	String s1(str1),s2(str2),s3;
	s3=s1+s2;
	s3.Display();
	cout<<s3[2]<<endl;
	s3[2]='z';
	cout<<s3[2]<<endl;
	return 0;
}
重载[]运算符时,我写了两个版本,一个可读可写,另一个起只读作用;
注意:只能重载为类成员的操作符有四个=、[]、()、->
5,输入输出重载
#include<iostream>

using namespace std;

class Complex
{
	public:
		Complex()
		{
			re=0;
			im=0;
		}
		Complex(double r,double i)
		{
			re=r;
			im=i;
		}
		Complex operator+(const Complex& obj);
		Complex operator!();
		friend ostream& operator<<(ostream &os,const Complex &c);
		friend istream& operator>>(istream &is,Complex &c);
	private:
		double re;
		double im;
};

Complex Complex::operator+(const Complex& obj)
{
	Complex temp;
	temp.re=re+obj.re;
	temp.im=im+obj.im;
	return temp;
}

Complex Complex::operator!()
{
	Complex temp;
	temp.re=-re;
	temp.im=-im;
	return temp;
}

ostream& operator<<(ostream &os,const Complex &c)
{
	os<<c.re;
	if(c.im>0)
		os<<"+"<<c.im<<"i"<<endl;
	else
		os<<c.im<<"i"<<endl;
	return os;
}

istream& operator>>(istream &is,Complex &c)
{
	is>>c.re>>c.im;
	return is;
}

int main(int argc,char *argv[])
{
	Complex obj1(1,2),obj2(3,4);
	Complex obj3=obj1+!obj2;
	cout<<obj3;

	cin>>obj3;
	cout<<obj3;
	return 0;
}
输入输出运算符的重载只能用友元函数的方式,应为隐式调用为cout<<Class_obj其中Class_obj为类类型Class_name的对象;如果用显示调用,则变成了cout.operator<<Class_obj,很显然cout本身不是Class_name的对象;
为了保证输出运算符<<的连用性,重载函数的返回应该为ostream&;对于重载>>,需要注意的是第二个参数必须是对象的引用;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值