重载operator=时关键的有三点:
(1)检查自赋值。
(2)调用基类的赋值函数。
(3)返回本对象的引用。
例1
template
// 名字和指针相关联的类的模板
class namedptr
{
public:
namedptr(const string& initname, t *initptr); //构造函数
namedptr& operator=(const namedptr& rhs); //赋值函数
private:
string name; //名称
t *ptr; //
};
template
namedptr
& namedptr
::operator=(const namedptr
& rhs)
{
if (this == &rhs) //检查自赋值
return *this; //直接 返回本对象的引用
// assign to all data members
name = rhs.name; // 给name赋值
*ptr = *rhs.ptr; // 对于ptr,赋的值是指针所指的值,
// 不是指针本身
return *this; // 返回本对象的引用
}
当有类继承时,情况复杂一些。派生类的赋值函数必须调用基类的赋值函数。
例2.
class base {
public:
base(int initialvalue = 0): x(initialvalue) {}
private:
int x;
};
class derived: public base {
public:
derived(int initialvalue)
: base(initialvalue), y(initialvalue) {} //派生类的构造函数之前包含基类的构造函数
derived& operator=(const derived& rhs); //派生类的构造函数
private:
int y;
};
也许你的赋值函数这样写
derived& derived::operator=(const derived& rhs)
{
if (this == &rhs) return *this;
y = rhs.y;
return *this;
}
但是这样写的话,没有给base类的变量赋值,直接写对base::x赋值也不允许,因为x是private类型的,下面的赋值函数是合理的。
derived& derived::operator=(const derived& rhs)
{
if (this == &rhs) return *this;
base::operator=(rhs); // 调用this->base::operator=
y = rhs.y;
return *this;
}
上述的operator=如果是编译器自动生成的,那么这种写法未必都能通的过,为了适应这种编译器,必须这样实现derived::operator=:
derived& derived::operator=(const derived& rhs)
{
if (this == &rhs) return *this;
static_cast(*this) = rhs; // 对*this的base部分
// 调用operator=
y = rhs.y;
return *this;
}
这段怪异的代码将*this强制转换为base的引用,然后对其转换结果赋值。这里只是对derived对象的base部分赋值。还要注意的重要一点是,转换的是base对象的引用,而不是base对象本身。如果将*this强制转换为base对象,就要导致调用base的拷贝构造函数,创建出来的新对象就成为了赋值的目标,而*this保持不变。这不是所想要的结果。
在派生类的拷贝构造函数也会发生类似的问题。
例3.
class base {
public:
base(int initialvalue = 0): x(initialvalue) {}
base(const base& rhs): x(rhs.x) {}
private:
int x;
};
class derived: public base {
public:
derived(int initialvalue)
: base(initialvalue), y(initialvalue) {}
derived(const derived& rhs) // 错误的拷贝构造函数
: y(rhs.y) {} //
private:
int y;
};
例3中派生类的拷贝构造函数,没有调用基类的拷贝构造函数,但是编译器会调用基类的缺省拷贝构造函数,没有顾及被拷贝对象。解决这个问题的办法就是在派生类的构造函数初始化列表中初始化base,派生类的定义应该如下所示:
class derived: public base {
public:
derived(int initialvalue)
: base(initialvalue), y(initialvalue) {}
derived(const derived& rhs) :base(rhs),y(rhs.y) // 正确的拷贝构造函数
{}
private:
int y;
};