zoukankan      html  css  js  c++  java
  • effective c++:对象的赋值运算

    operator 中处理”自我赋值“

    operator=操作符缺省情况下返回引用——TYPE& TYPE::operator=(const TYPE&),原因很简单,operator=返回引用的理由是使你能在一个语句中连接多个赋值。

    int x, y, z;
    x = y = z = 15; // chain of assignments

    赋值采用右结合律,上面的代码被编译器解释为:

    x = (y = (z = 15));

    在编译过程中,赋值是右结合的。说白了就是如果你想要玩一下多个赋值,operator=返回的东西必须是右(rhs)赋值。除了返回对对象自身的引用还能有什么呢?这就是为什么operator=最后一行总是返回对this的引用:

    class Widget {
    public:
      ...
      Widget& operator=(const Widget& rhs) // return type is a reference to
      { // the current class
      ...
      return *this; // return the left-hand object
      }
      ...
    };

    再来看自我赋值,即对象被赋值给自己,假设建立一个class用来保存一个指针指向一块动态分配的bitmap

    class Bitmap { ... };
    class Widget {
      ...
      private:
      Bitmap *pb; // ptr to a heap-allocated object
    };

    下面是operator=代码,表面上看合理,但自我赋值时并不安全。

    Widget&
    Widget::operator=(const Widget& rhs) // unsafe impl. of operator=
    {
      delete pb; // stop using current bitmap
      pb = new Bitmap(*rhs.pb); // start using a copy of rhs’s bitmap
      return *this; // see Item 10
    }

    如果rhs与*this指向同一对象,第一句的delete pb就销毁了bitmap中调用的rhs.pb,这一问题的解决方案是copy and swap:

    class Widget {
    ...
    void swap(Widget& rhs); // exchange *this’s and rhs’s data;
    ... // see Item29 for details
    };
    Widget& Widget::operator=(const Widget& rhs)
    {
      Widget temp(rhs); // make a copy of rhs’s data
      swap(temp); // swap *this’s data with the copy’s
      return *this;
    }

    它先将rhs做一个复本,由这个复本与this交换数据来达到目的。

    复制对象时确保复制对象内每个成员变量

    类customer如下所示:

    void logCall(const std::string& funcName); // make a log entry
    class Customer {
    public:
      ...
      Customer(const Customer& rhs);
      Customer& operator=(const Customer& rhs);
      ...
    private:
      std::string name;
    };
    Customer::Customer(const Customer& rhs)
      : name(rhs.name) // copy rhs’s data
    {
      logCall("Customer copy constructor");
    }
    Customer& Customer::operator=(const Customer& rhs)
    {
      logCall("Customer copy assignment operator");
      name = rhs.name; // copy rhs’s data
      return *this; // see Item 10
    }

    这个程序完全正确,但当在类中加入一个成员变量,我们同时也要在复制运算中加入相应的变量复制。

    class Date { ... }; // for dates in time
    class Customer {
    public:
      ... // as before
    private:
      std::string name;
      Date lastTransaction;
    };

    如果忘记修改operator=函数,编译器不会提醒你,从而造成潜在的漏洞。

    再来看派生类复制的情况

    class PriorityCustomer: public Customer { // a derived class
    public:
      ...
      PriorityCustomer(const PriorityCustomer& rhs);
      PriorityCustomer& operator=(const PriorityCustomer& rhs);
      ...
    private:
      int priority;
    };
    PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
    : priority(rhs.priority)
    {
      logCall("PriorityCustomer copy constructor");
    }
     PriorityCustomer&
    PriorityCustomer::operator=(const PriorityCustomer& rhs)
    {
      logCall("PriorityCustomer copy assignment operator");
      priority = rhs.priority;
      return *this;
    }
    PriorityCustomer好像是完全复制了成员变量,但每个PriorityCustomer类都还包含着基类的成员变量未被复制,PriorityCustomer类中的customer成分被不带实参的customer构造函数初始化,customer成员变量初始化为缺省的值。我们所要做的是提供一个第三方的函数来调用基类的复制函数。

    注意两个错误用法:1、令copy assignment操作符调用copy构造函数是错误的,因为在这就像试图构造一个已存在的对象。2、令copy构造函数调用copy assignment操作符同样是错误的。构造函数用来出事后对象,而assignment操作符只实行与已初始化的对象身上。对一个尚未构造好的对象赋值,就像在一个尚未初始化的对象身上做“z只对已初始化对象才有意义”的事意义。

  • 相关阅读:
    Centos(Linux)安装openoffice教程
    IDEA快速创建一个简单的SpringBoot项目(需要联网)
    Maven配置使用阿里云镜像
    关于Spring MVC的问题
    FTP搭建YUM源服务器
    IP子网的划分
    交换分区swap
    sentos7忘记root密码,重置密码
    sentos中bonding(网卡绑定技术)1
    sentos7网卡改名
  • 原文地址:https://www.cnblogs.com/loujiayu/p/3599236.html
Copyright © 2011-2022 走看看