1、赋值运算符函数的概念
对任一类X,如果用户没有自定义的赋值运算符函数,那么编译系统将自动地为其生成一个默认的赋值运算符函数,默认赋值运算符函数重载形式如下:
X&X :: operator = ( const X & source )
{
成员间赋值
}
2、重载赋值运算符解决赋值不兼容问题
重载赋值运算符解决赋值不兼容问题,应该注意两点:
(1)赋值运算符必须重载为成员函数
(2) 为了保持与通常意义下的赋值运算符的功能相一致,应该让重载的赋值运算符仍然能连续使用,所以operator =函数通常要返回引用
【示例】为myComplex重载赋值运算符
#include <iostream>
#include<string>
using namespace std;
class myComplex
{
private:
double real,imag;
public:
myComplex ();
myComplex(double r,double i) ;
~myComplex(){}
myComplex addCom(myComplex c1); //成员函数,调用对象与参数对象c1相加
void outCom(); //成员函数
void outCom(string s); //成员函数
void changReal(double r); //成员函数
friend myComplexoperator+(const myComplex &cl,const myComplex &c2);//c1+c2
friend myComplex operator+(const myComplex &c1,double r) ;//c1+r
friend myComplex operator+(double r,const myComplex &c1); //r+cl
friend myComplex operator-(const myComplex &cl,const myComplex &c2);//c1-c2
friend myComplex operator-(const myComplex 6cl,double r); //c1-r
friend myComplex operator-(double r,const myComplex &cl); //r-cl
myComplex &operator=(const myComplex &c); //成员函数
myComplex &operator=(double); //成员函数
};
myComplex::myComplex ()
{
real =0;
imag =0;
}
myComplex::myComplex (double r, double i)
{
real = r;
imag = i;
}
myComplex myCgmplex::addCom (myComplex c1)
{
return myComplex(this->real+cl.real+cl.real,this->imag+cl.imag);
}
void myComplex::outCom()
{
cout<<"("<<real<<","<<imag<<")";
}
void myComplex::outCom(string s)
{
cout<<s<<"=("<<real<<","<<imag<<")"<<endl;
}
void myComplex::changReal(double r)
{
this->real=r;
}
myComplex operator+(const myComplex &cl,const myComplex &c2) //c1+c2
{
return myComplex(cl.real+c2.real,cl.imag+c2.imag); //返回一个临时对象
}
myComplex operator+(const myComplex &c1,double r) //c1+r
{
return myComplex(cl.real,cl.imag+r); //返回一个临时对象
}
myComplex operator+(double r,const myComplex &c1) //r+c1
{
return myComplex(r+cl.real,c1.imag); //返回一个临时对象
}
myComplex operator-(const myComplex &cl,const myComplex &c2) //c1-c2
{
return myComplex(cl.real-c2.real,cl.imag-c2.imag); //返回一个临时对象
}
myComplex operator-(const myComplex &c1,double r) //c1-r
{
return myComplex(cl.real-r,c1.imag); //返回一个临时对象
}
myComplex operator-(double r,const myComplex &c1)//r-c1
{
return myComplex(r-cl.real,-c1.imag); //返回一个临时对象
}
myComplex &myComplex::operator =(const myComplex &c1)
{
this->real=c1.real;
this->imag=c1.imag;
return *this;
}
myComplex &myComplex::operator =(double r)
{
this->real=r;
this->image;
return *this;
}
int main()
{
myComplex c1(1,2),c2(3,4),res;
c1.outCom("\t\t\tc1"); //c1=(1,2);
c2.outCom("\t\t\tc2") ;
res=c1+c2;
res,outCom("执行res=c1+c2->\tres");
res=c1.addCom(c2);
res.outCom("执行res=c1,addCom(c2)->\tres") ;
res=c1+5;
res.outCom("执行res=c1+5->\tres");
res=5+c1;
res.outCom("执行res=c1+c2->\tres") ;
res=c1; //调用成贝两数必须通过老对象
c1.outCom(" t\t\tc1");
res,outCom("执行res=cl->\tres") ;
c1.changReal(-3);
res.outCom("执行res=cl,addCom(-3)->\tcl") ;
c1.outCom(" t\t\tres") :
res=c1;
res.outCom("执行res=c1->\tres") ;
res.butCom("执行res=7->\tres");
res=7+8;
res.outCom("执行res=(7+8)->\tres");
res=c1=c2;
cl.outCom("\t\t\tc1");
c2 .outCom("\t\t\tc2");
res,outCom("执行res=cl=c2->\tres");
return 0;
}
【运行结果】
c1=(1,2)
c2=(3,4)
执行res=c1+c2-> res=(4,6)
执行res=cl.addCom(c2)-> res=(7,6)
执行res=c1+5-> res=(1,7)
执行res=c1+c2-> res=(6,2)
c1=(1,2)
执行res=c1-> res=(1,2)
执行res=cl.addCom(-3)-> c1=(1,2)
res=(-3,2)
执行res=c1-> res=(-3,2)
执行res=7-> res=(7,0)
执行res=(7+8)-> res=(15,0)
c1=(3,4)
c2=(3,4)
执行res=c1=c2-> res=(3,4)
3、浅拷贝和深拷贝
(1)浅拷贝
浅拷贝:同类对象之间可以通过赋值运算符“=”相互赋值,如果没有经过重载,“=”的作用就是将赋值号右侧对象的值一一赋值给左侧的对象,这相当于值的拷贝,称为浅拷贝。
【示例】浅拷贝的含义
#include<iostream>
using namespace std;
class pointer
{
public:
int a;
int*p; //指向整型数的指针
pointer()
{
a=100;
p=new int(10);
}
pointer(const pointer &tempp)
{
if(this != &tempp)
{
a=tempp.a;
p=tempp.P;
}
}
};
int main ()
{
pointer p1; //使用默认构造函数
pointer p2(P1); //使用复制构造函数
pointer p3=p1;//复制构造函数
cout<<" \n初始化后,各对象的值及内存地址"<<endl;
cout<<"对象名\t对象地址: a的值 p中的值 p指向的值 p的地址"<<end1;
cout<<"p1:\t"<<&pl<<","<<pl,a<<","<<pl.p<<","<<*pl.p<<","<<&pl.p<<endl;
cout<<"p2:\t"<<&p2<<","<<p2.a<<","<<P2.p<<","<<*p2.p<<","<<&p2.p<<end1;
cout<<"p3:\t"<<&p3<<","<<p3.a<<","<<p3.p<<","<<*p3.p<<","<<&p3.p<<end1;
*p1.p=20;
p2.a=300;
cout<<"\n修改后,各对象的值及内存地址"<<endl:
cout<<"对象名\t对象地址: a的值 p中的值 p指向的值 p的地址:"<<endl;
cout<<"p1:\t"<<&pl<<","<<pl,a<<","<<pl.p<<","<<*pl.p<<","<<&pl.p<<endl;
cout<<"p2:\t"<<&p2<<","<<p2.a<<","<<P2.p<<","<<*p2.p<<","<<&p2.p<<end1;
cout<<"p3:\t"<<&p3<<","<<p3.a<<","<<p3.p<<","<<*p3.p<<","<<&p3.p<<end1;
return 0;
}
【运行结果】
初始化后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
pl: 0x6afed8,100,0xb70d60,10,0x6afedc
p2: 0x6afed0,100,0xb70d60,10,0x6afed4
p3: 0x6afec8,100,0xb70d60,10,0x6afecc
修改后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
pl: 0x6afed8,100,0xb70d60,20,0x6afedc
p2: 0x6afed0,300,0xb70d60,20,0x6afed4
p3: 0x6afec8,100,0xb70d60,20,0x6afecc
(2)深拷贝
深拷贝:重载赋值运算符,赋值语句的功能是将一个对象中指针成员变量指向的内容复制到另一个对象中指针成员变量指向的地方。
【示例】深拷贝的实现
#include<iostream>
using namespace std;
class pointer
{
public:
int a;
int *p; //指向整型数的指针
pointer()
{
a=100;
p=new int(10);
}
pointer(const pointer &tempp) //复制构造函数
{
if(this != &tempp)
{
a=tempp.a;
p=new int();
*p=*tempp.p;
}
}
~pointer()
{
if(p!=NULL) delete p;
}
pointer &operator=(const pointer &c)//成员函数
{
if(this == &c) return *this; //避免a=a这样的赋值
delete this->p; //释放原来的空间
this->p = new int(*c.p); //申请新空间保存值
return *this ;
}
};
int main()
{
pointer p1; //使用默认构造函数
pointer p2(P1); //使用复制构造函数
pointer p3;
p1=p1;//用来测试
p3=p1;//使用复制构造函数
cout<<" \n初始化后,各对象的值及内存地址"<<endl;
cout<<"对象名\t对象地址: a的值 p中的值 p指向的值 p的地址"<<end1;
cout<<"p1:\t"<<&pl<<","<<pl,a<<","<<pl.p<<","<<*pl.p<<","<<&pl.p<<endl;
cout<<"p2:\t"<<&p2<<","<<p2.a<<","<<P2.p<<","<<*p2.p<<","<<&p2.p<<end1;
cout<<"p3:\t"<<&p3<<","<<p3.a<<","<<p3.p<<","<<*p3.p<<","<<&p3.p<<end1;
*p1.p=20;
p2.a=300;
cout<<"\n修改后,各对象的值及内存地址"<<endl:
cout<<"对象名\t对象地址: a的值 p中的值 p指向的值 p的地址:"<<endl;
cout<<"p1:\t"<<&pl<<","<<pl,a<<","<<pl.p<<","<<*pl.p<<","<<&pl.p<<endl;
cout<<"p2:\t"<<&p2<<","<<p2.a<<","<<P2.p<<","<<*p2.p<<","<<&p2.p<<end1;
cout<<"p3:\t"<<&p3<<","<<p3.a<<","<<p3.p<<","<<*p3.p<<","<<&p3.p<<end1;
return 0;
}
【运行结果】
初始化后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
pl: 0x6afed8,100,0xb70d60,10,0x6afedc
p2: 0x6afed0,100,0xb70d60,10,0x6afed4
p3: 0x6afec8,100,0xb70d60,10,0x6afecc
修改后,各对象的值及内存地址
对象名 对象地址 a的值 p中的值 p指向的值 p的地址
pl: 0x6afed8,100,0xb70d60,20,0x6afedc
p2: 0x6afed0,300,0xb70d60,10,0x6afed4
p3: 0x6afec8,100,0xb70d60,10,0x6afecc
4、例题
例题1:[完成程序题] 完成下面类中成员函数的定义。
#include <iostrcam.h>
#include <string>
using namespace std ;
class str
{
private :
char *st;
public:
str(char *a){ set(a); }
str & operator = (______(1)_______)
{
delete st;
sct(a.st);
return this;
}
void show( )
{
cout << st << endl;
}
~str( ){ delete st;}
void set(char *s)//初始化 st
{
____________(2)_____________;
&strcpy(st,s);
}
};
void main()
{
str s1("he"),s2("she");
sl. show(),s2.show();
s2 = sl;
sl. show( ),s2. show() ;
}
【正确答案】:
(1) str &a
(2) st = new char[strlen(s)+1]
例题2:[单选题]对赋值运算符进行重载时,应声明为_______________函数。
【正确答案】:成员
【答案解析】:重载赋值运算符,只能重载为成员函数