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;
};
(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;
};
相关文章推荐
- Effective C++ 条款16: 在operator=中对所有数据成员赋值
- effective C++笔记之条款16: 在operator=中对所有数据成员赋值
- 条款十六: 在operator=中对所有数据成员赋值
- 条款 16: 在 operator=中对所有数据成员赋值
- 在operator=中对所有数据成员赋值
- 条款16: 在operator=中对所有数据成员赋值
- 在operator=中对所有数据成员赋值
- 在operator=或拷贝构造中对所有数据成员赋值
- 在operator=中对所有数据成员赋值
- C++ Primer 学习笔记_54_类与数据抽象 -复制构造函数、赋值操作符
- C++ Primer 学习笔记_60_满载操作符与转换 -赋值、下标、成员访问操作符
- Effective C++学习笔记:尽量使用初始化而不要在构造函数里赋值
- [学习笔记]c#Primer中文版-类设计、static成员、const和readonly数据成员
- Effective C++学习笔记:初始化列表中成员列出的顺序和它们在类中声明的顺序相同
- Effective c++学习笔记——条款10:令operator=返回一个*this的引用
- Effective C++_笔记_条款11_在operator=中处理“自我赋值”
- 安卓学习笔记---如何保存数据到SharePreference里面,获取所有sp文件以及删除文件
- Effective C# 学习笔记(十二) 多用成员变量初始化,少用指定赋值
- Effecticve学习笔记_条款45:运用成员函数模板接收所有兼容类型
- Effective C++ 学习笔记:让operator=返回*this的引用