资源描述
赋值运算符重载
虽然一个对象可以由一个单一的赋值语句赋值给另一个对象,我们
之前提到的,此操作可能只创建一个逻辑复制(即,由一个成员
复印件)。
在一个逻辑复制,在一个对象的成员将该成员的值在其他
对象。如果一个类有一个指针成员,由成员复印件使
指针成员在两个对象指向同一个对象。
有两个问题与此成员对成员的复制:第一,因为指针在两个
对象共享相同的变量,这个变量的变化而变化的对象。在其他
的话,这两个对象都不是独立的。
第二,如果共享变量在堆上,我们不知道谁是负责
释放内存。这记忆是不自由的,也将是免费的两倍,这是不
允许。
当一个类成员是一个指向堆内存,我们通常需要过载
赋值操作符来创建一个物理副本。
实例1:
//说明动态内存分配的默认分配的危险。
#include <iostream.h>
#include <string.h>
const int MAX_CHAR = 10;
class Account
{
friend ostream& operator<<(ostream& os, Account &b);
public:
Account ( char* name ="unknown",
char * mr = "Miss", float y=0.0)
{ title= new char[strlen(mr)+1];
strcpy(title,mr);
strcpy(owner, name);
balance = y;
}
void changetitle(char* newname)
{
if( strlen(newname) > strlen(title) )
{
char* tmp = title;
title = new char[strlen(newname)+1];
strcpy (title,newname);
delete []tmp;
}
else
{
strcpy (title,newname);
}
}
void changename(char* newname)
{strcpy (owner,newname);}
~Account () {delete [ ] title;}
private:
char * title;
char owner[MAX_CHAR];
float balance;
};
ostream& operator<< (ostream& os, Account &b)
{
os <<"who:"<< b.title << " " << b.owner
<<" how much="<<b.balance<<"\n";
os << endl;
return os;
}
void main(){
Account acc("Lou","Mr", 100);
Account acc1;
cout << acc;
cout << acc1;
acc1=acc;
cout << acc1;
acc1.changename("jean");
cout << acc1;
cout<<acc;
acc1.changetitle("Dr.");
cout << acc1;
cout<<acc;
}
Output
who: Mr Lou how much = 100
who: Miss unknown how much = 0
who: Mr Lou how much = 100
who: Mr Jean how much = 100
who: Mr Lou how much = 100
who: Dr. Jean how much = 100
who: Dr. Lou how much = 100
Then: Run time error: trying to delete same memory twice. If
we delete our destructor, then memory leak. The dynamic
memory is not deleted//运行时错误:试图删除该内存的两倍。如果
我们删除我们的析构函数,然后内存泄漏。动态记忆是不会被删除.
解决方案:重载赋值运算符来得到一个完全不同的
复制包括其自己的堆内存:
(深拷贝)。
在一个类的赋值操作符重载,我们通常需要做的四件事:
首先,我们要检查一个对象是否是分配给本身。(这是可能的因为
变量可以通过不同的名字来访问)。如果是分配给本身,我们不
要做什么。
如果它不是一个自的任务,我们必须释放堆内存的指针成员
对象的当前点。
然后,我们复制的右边的左边。
最后,我们返回*this便于分配链接。返回类型是一个常数
参考因为我们要返回原对象(参考),我们不希望它
被用作左值(常数)。如果返回值是不固定的,我们可以
这样的表达式(X = Y)= Z,这实际上意味着,我们分配的Z值的
返回值(X = Y)。换句话说,我们指定Y = X,然后将Z X再次,
这没有意义。
赋值操作符重载函数必须是成员函数。
这4个运算符是真实的:=,(),[ ],->
实例2:
//这个例子定义了类的向量的第二版,具有过载
运算符=,/ / [ ]和<<。
#include <iostream.h>
class Vector
{
public:
Vector(int s, int an_array[ ]); // a constructor
~ Vector( )
{
delete [ ] rep;
} // a destructor
int get_size( ) const {return size;} // an accessor
const Vector& operator=(const Vector& x);
int& operator[ ](int index) {return rep[index];}
llconst int& operator[ ](int index) const {return rep[index];}
private:
int *rep;
int size;
};
// A constructor initializing the members of rep by the
parameter an_array
Vector:: Vector(int s, int an_array[ ]):size(s), rep(new
int[s])
{
for (int i = 0; i < size; ++i)
{
rep[i] = an_array[i];
}
}
// Note that the initializer uses new int[s] to initialize
rep, but not new int[size]
// because the initializers may not be evaluated in the
specified order.
const Vector& Vector::operator=(const Vector& x)
{
if( this != &x)
{
size = x.size;
delete [ ] rep; // clean up the old one.
rep = new int[size];
for (int i = 0; i < size; ++i)
{
rep[i] = x.rep[i];
}
}
/*size = x.size;
if (rep != x.rep)
{
delete [ ] rep; // clean up the old one.
rep = new int[size];
for (int i = 0; i < size; ++i)
{
rep[i] = x.rep[i];
}
}*/
return *this;
}
ostream& operator<<(ostream& out, const Vector& x)
{
int s = x.get_size( );
for (int i = 0; i < s; ++i)
{
out << x[i]<<endl;
}
return out;
}
请注意,在这个类中,矢量是通过一个动态数组表示。赋值操作符,
复制构造函数和析构函数是必要的。在类向量以前的版本,我们
不需要这些功能,因为一个物理副本将由编译器创建的如果
分配或复制发生。
操作员+ =。+,* =,和/ =也以同样的方式超载。我们也可以使用这些
运算符过载算子。例如,我们可以实现运算符+ =在
复合类如下:
const Complex& Complex::operator+= (const Complex& c)
{
r += c._r;
i += c._i;
return *this;
}
Then, the operator + can be overloaded as the following:
const Complex operaotr+ (const Complex& c1, const Complex&
c2)
{
Complex temp(c1);
temp += c2;
return temp;
}
Or, implement it as a member function:
const Complex Complex::operator+(const Complex& c) const
{
Complex temp(*this);
temp += c;
return temp;
}
ll
ll
ll
展开阅读全文