C++ Primer Plus学习笔记之运算符重载
时间:2014-05-04 09:21:08
收藏:0
阅读:455
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&;对于重载>>,需要注意的是第二个参数必须是对象的引用;
评论(0)