您的位置:首页 > 编程语言 > C语言/C++

Effective C++学习笔记:在operator=中对所有数据成员赋值

2008-01-23 16:29 531 查看
重载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;

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: