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

重载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;

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值