欣乐

The eagles are coming!

导航

第十三章 复制控制

code:

 

 

 

 

/*


第13章 复制控制
13.1 复制构造函数
13.2 赋值操作符
13.3 析构函数
13.4 消息处理示例
13.5 管理指针成员
小结





第13章 复制控制 405
13.1 复制构造函数 406
13.1.1 合成的复制构造函数 409
13.1.2 定义自己的复制构造函数 409
13.1.3 禁止复制 410
13.2 赋值操作符 411
13.3 析构函数 412
13.4 消息处理示例 415
13.5 管理指针成员 419
13.5.1 定义智能指针类 421
13.5.2 定义值型类 425
小结 427
术语 427


*/




//13.1 复制构造函数 -------------------------------------------------------------------------------------------------



// 如果我们没有定义复制构造函数,编译器就会为我们合成一个。合成的效果如同:
#include <iostream>
#include <string>
using namespace std;

class Sales_item
{
  public:
    Sales_item::Sales_item(const Sales_item &orig):
      isbn(orig.isbn),             // uses string copy constructor
      units_sold(orig.units_sold), // copies orig.units_sold
    revenue(orig.revenue)          // copy orig.revenue
    {}                             // empty body
  // other members and constructors as before
  private:
    std::string isbn;
    int units_sold;
    double revenue;
};

int main()
{
  return 0;
}



//13.2 赋值操作符 -------------------------------------------------------------------------------------------------

/*
重载操作符是一些函数,其名字为 operator 后跟着所定义的操作符的符号。因此,通过定义名为 operator= 的函数,
我们可以对赋值进行定义。像任何其他函数一样,操作符函数有一个返回值和一个形参表。形参表必须具有与该操作符数目
相同的形参(如果操作符是一个类成员,则包括隐式 this 形参)。赋值是二元运算,所以该操作符函数有两个形参:
第一个形参对应着左操作数,第二个形参对应右操作数。
大多数操作符可以定义为成员函数或非成员函数。当操作符为成员函数时,它的第一个操作数隐式绑定到 this 指针。
有些操作符(包括赋值操作符)必须是定义自己的类的成员。因为赋值必须是类的成员,所以 this 绑定到指向左操作数的指针。
因此,赋值操作符接受单个形参,且该形参是同一类类型的对象。右操作数一般作为 const 引用传递。
*/

#include <iostream>
#include <string>
using namespace std;

class Sales_item
{
  public:
    // other members as before
    // equivalent to the synthesized assignment operator
    Sales_item &operator = (const Sales_item &); // 声明
};

int main()
{
  return 0;
}


// =
#include <iostream>
#include <string>
using namespace std;

class Sales_item
{
  public:
    // other members as before
    // equivalent to the synthesized assignment operator
    Sales_item &operator = (const Sales_item &); // 声明
  private:
    std::string isbn;
    int units_sold;
    double revenue;
};

// equivalent to the synthesized assignment operator
Sales_item &Sales_item::operator = (const Sales_item &rhs) // 定义
{
  isbn = rhs.isbn; // calls string::operator=
  units_sold = rhs.units_sold; // uses built-in int assignment
  revenue = rhs.revenue; // uses built-in double assignment
  return  *this;
}

int main()
{
  return 0;
}



//13.3 析构函数 -------------------------------------------------------------------------------------------------

/*
如果类需要析构函数,则它也需要赋值操作符和复制构造函数,这是一个有用的经验法则。这个规则常称为三法则,
指的是如果需要析构函数,则需要所有这三个复制控制成员。
析构函数与复制构造函数或赋值操作符之间的一个重要区别是,即使我们编写了自己的析构函数,合成析构函数仍然运行。
*/


//13.4 消息处理示例 -------------------------------------------------------------------------------------------------


// in book,本身就缺少 save...

#include <iostream>
#include <string>
using namespace std;

class Message
{
  public:
    // folders is initialized to the empty set automatically
    Message(const std::string &str = ""): contents(str){}
    // copy control: we must manage pointers to this Message
    // from the Folders pointed to by folders
    Message(const Message &);
    Message &operator = (const Message &);
    ~Message();
    // add/remove this Message from specified Folder's set of messages
    void save(Folder &);
    void remove(Folder &);
  private:
    std::string contents; // actual message text
    std::set < Folder * > folders; // Folders that have this Message
    // Utility functions used by copy constructor, assignment, and destructor:
    // Add this Message to the Folders that point to the parameter
    void put_Msg_in_Folders(const std::set < Folder * >  &);
    // remove this Message from every Folder in folders
    void remove_Msg_from_Folders();
};

Message::Message(const Message &m): contents(m.contents), folders(m.folders)
{
  // add this Message to each Folder that points to m
  put_Msg_in_Folders(folders);
}

// add this Message to Folders that point to rhs
void Message::put_Msg_in_Folders(const set < Folder * >  &rhs)
{
  for(std::set < Folder * > ::const_iterator beg = rhs.begin(); beg != rhs.end()
    ; ++beg)
    (*beg)->addMsg(this);
  // *beg points to a Folder
}

Message &Message::operator = (const Message &rhs)
{
  if(&rhs != this)
  {
    remove_Msg_from_Folders(); // update existing Folders
    contents = rhs.contents; // copy contents from rhs
    folders = rhs.folders; // copy Folder pointers from rhs
    // add this Message to each Folder in rhs
    put_Msg_in_Folders(rhs.folders);
  }
  return  *this;
}

// remove this Message from corresponding Folders
void Message::remove_Msg_from_Folders()
{
  // remove this message from corresponding folders
  for(std::set < Folder * > ::const_iterator beg = folders.begin(); beg !=
    folders.end(); ++beg)
    (*beg)->remMsg(this);
  // *beg points to a Folder
}

Message::~Message()
{
  remove_Msg_from_Folders();
}

int main()
{
  return 0;
}


// 还要添加Folder类等,未完成
#include <iostream>
#include <string>
#include <set>
using namespace std;

class Message
{
  public:
    // contents初始化为空串
    Message(const string &str = ""): contents(str){}
    Message(const Message &); // 复制构造函数
    Message &operator = (const Message &); // 重载赋值运算符
    ~Message(); // 析构函数
    void save(Folder &); // 添加信息
    void remove(Folder &); // 移除信息
  private:
    string contents; // 信息文本内容
    set < Folder * > folders; // folders 是 Folder的指针集合
    void put_Msg_in_Folders(const std::set < Folder * >  &); // 将信息指针,加入folders集合
    void remove_Msg_from_Folders(); // 将信息指针,从folders集合中移除
};

// 复制构造函数
Message::Message(const Message &m) : contents(m.contents), folders(m.folders)
{
  // add this Message to each Folder that points to m
  put_Msg_in_Folders(folders);
}

// add this Message to Folders that point to rhs
void Message::put_Msg_in_Folders(const set < Folder * >  &rhs)
{
  for(set < Folder * > ::const_iterator beg = rhs.begin();
    beg != rhs.end(); ++beg)
    (*beg)->addMsg(this); // ??
  // *beg points to a Folder
}

// 重载赋值运算符
Message &Message::operator = (const Message &rhs)
{
  if(&rhs != this)
  {
    remove_Msg_from_Folders(); // update existing Folders
    contents = rhs.contents;   // copy contents from rhs
    folders = rhs.folders;     // copy Folder pointers from rhs
    // add this Message to each Folder in rhs
    put_Msg_in_Folders(rhs.folders);
  }
  return  *this;
}

// remove this Message from corresponding Folders
void Message::remove_Msg_from_Folders()
{
  // remove this message from corresponding folders
  for(std::set < Folder * > ::const_iterator beg = folders.begin();
    beg !=folders.end(); ++beg)
    (*beg)->remMsg(this);
  // *beg points to a Folder
}

Message::~Message()
{
  remove_Msg_from_Folders();
}

int main()
{
  return 0;
}


//13.5 管理指针成员 -------------------------------------------------------------------------------------------------


// my test
#include <iostream>
#include <string>
using namespace std;

int main()
{
  int i(3);
  int *pa, *pb;
  pa=&i; pb=&i;
  *pa = 0; // 任一指针,都可以改变原来的指向内容
  cout << *pb << endl;
  
  return 0;
}



// in book
#include <iostream>
#include <string>
using namespace std;
// class that has a pointer member that behaves like a plain pointer
class HasPtr
{
  public:
    // copy of the values we're given
    HasPtr(int *p, int i): ptr(p), val(i){}
    
    // const members to return the value of the indicated data member
    int *get_ptr()const { return ptr; } 
    int get_int()const  { return val; }
    
    // non const members to change the indicated data member
    void set_ptr(int *p) { ptr = p; }
    void set_int(int i)  { val = i; }
    
    // return or change the value pointed to, so ok for const objects
    int get_ptr_val()const { return  *ptr; }
    void set_ptr_val(int val)const { *ptr = val; }
    
  private:
    int *ptr;
    int val;
};

int main()
{
  int i(3);
  HasPtr cptr(&i,i);
  cout << cptr.get_ptr() << endl; // 地址
  cout << cptr.get_int() << endl; //
  cout << cptr.get_ptr_val() << endl; //
  cptr.set_ptr_val(8);
  cout << cptr.get_ptr_val() << endl; ////
  int j(10);
  cptr.set_ptr(&j);
  cout << cptr.get_ptr_val() << endl;
  
  return 0;
}


// 指针复制
#include <iostream>
#include <string>
using namespace std;
// class that has a pointer member that behaves like a plain pointer
class HasPtr
{
  public:
    // copy of the values we're given
    HasPtr(int *p, int i): ptr(p), val(i){}
    
    // const members to return the value of the indicated data member
    int *get_ptr()const { return ptr; } 
    int get_int()const  { return val; }
    
    // non const members to change the indicated data member
    void set_ptr(int *p) { ptr = p; }
    void set_int(int i)  { val = i; }
    
    // return or change the value pointed to, so ok for const objects
    int get_ptr_val()const { return  *ptr; }
    void set_ptr_val(int val)const { *ptr = val; }
    
  private:
    int *ptr;
    int val;
};

int main()
{
  int obj = 0;
  HasPtr ptr1(&obj, 42); // int* member points to obj, val is 42
  cout << ptr1.get_ptr() << endl; // ptr1.ptr
  HasPtr ptr2(ptr1);     // int* member points to obj, val is 42
  cout << ptr2.get_ptr() << endl; // ptr2.ptr
  // 我们会发现,两个地址一模一样,复制的嘛
  
  return 0;
}


// in book
#include <iostream>
#include <string>
using namespace std;

// class that has a pointer member that behaves like a plain pointer
class HasPtr
{
  public:
    // copy of the values we're given
    HasPtr(int *p, int i): ptr(p), val(i){}
    
    // const members to return the value of the indicated data member
    int *get_ptr()const { return ptr; } 
    int get_int()const  { return val; }
    
    // non const members to change the indicated data member
    void set_ptr(int *p) { ptr = p; }
    void set_int(int i)  { val = i; }
    
    // return or change the value pointed to, so ok for const objects
    int get_ptr_val()const { return  *ptr; }
    void set_ptr_val(int val)const { *ptr = val; }
    
  private:
    int *ptr;
    int val;
};

int main()
{
  int obj = 0;
  HasPtr ptr1(&obj, 42); // int* member points to obj, val is 42
  HasPtr ptr2(ptr1); // int* member points to obj, val is 42
  
  ptr1.set_int(0); // changes val member only in ptr1
  cout << ptr2.get_int() << endl; // returns 42
  cout << ptr1.get_int() << endl; // returns 0
  // 说明整数副本是独立的
  
  ptr1.set_ptr_val(42); // sets object to which both ptr1 and ptr2 point
  cout << ptr1.get_ptr_val() << endl; // returns 42
  cout << ptr2.get_ptr_val() << endl; // returns 42
  // 因为两指针值得是一样的,所以两val都一样了
  
  int *ip = new int(42); // dynamically allocated int initialized to 42
  HasPtr ptr(ip, 10); // Has Ptr points to same object as ip does
  delete ip; // object pointed to by ip is freed
  ptr.set_ptr_val(0); // disaster: The object to which Has Ptr points was freed!
  
  return 0;
}


// 13.5.1. 定义智能指针类

#include <iostream>
#include <string>
using namespace std;

// private class for use by HasPtr only
class U_Ptr {
    friend class HasPtr;
    int *ip;
    size_t use;
    U_Ptr(int *p): ip(p), use(1) { }
    ~U_Ptr() { delete ip; }
};

/*smart pointer class: takes ownership of the dynamically allocated
*   object to which it is bound
* User code must dynamically allocate an object to initialize a HasPtr
* and must not delete that object; the HasPtr class will delete it
*/
class HasPtr {
  public:
    // HasPtr owns the pointer; p must have been dynamically allocated
    HasPtr(int *p, int i): ptr(new U_Ptr(p)), val(i) { }

    // copy members and increment the use count
    HasPtr(const HasPtr &orig):
      ptr(orig.ptr), val(orig.val) { ++ptr->use; } // add use
    HasPtr& operator=(const HasPtr&);

    // if use count goes to zero, delete the U_Ptr object
    ~HasPtr() { if (--ptr->use == 0) delete ptr; }


    // copy control and constructors as before
    // accessors must change to fetch value from U_Ptr object
    int *get_ptr() const { return ptr->ip; }
    int get_int() const { return val; }

    // change the appropriate data member
    void set_ptr(int *p) { ptr->ip = p; }
    void set_int(int i) { val = i; }

    // return or change the value pointed to, so ok for const objects
    // Note: *ptr->ip is equivalent to *(ptr->ip)
    int get_ptr_val() const { return *ptr->ip; }
    void set_ptr_val(int i) { *ptr->ip = i; }

  private:
    U_Ptr *ptr;  // points to use-counted U_Ptr class
    int val;
};

HasPtr &HasPtr::operator = (const HasPtr &rhs)
{
  ++rhs.ptr->use; // increment use count on rhs first
  if(--ptr->use == 0)
    delete ptr;
  // if use count goes to 0 on this object, delete it
  ptr = rhs.ptr; // copy the U_Ptr object
  val = rhs.val; // copy the int member
  return  *this;
}


int main()
{
 
  return 0;
}



// 13.5.2. 定义值型类

// in book
#include <iostream>
#include <string>
using namespace std;

/*
* Valuelike behavior even though HasPtr has a pointer member:
* Each time we copy a HasPtr object, we make a new copy of the
* underlying int object to which ptr points.
*/
class HasPtr {
  public:
    // no point to passing a pointer if we're going to copy it anyway
    // store pointer to a copy of the object we're given
    HasPtr(const int &p, int i): ptr(new int(p)), val(i) {}

    // copy members and increment the use count
    HasPtr(const HasPtr &orig):
      ptr(new int (*orig.ptr)), val(orig.val) {}

    HasPtr& operator=(const HasPtr&);
    ~HasPtr() { delete ptr; }
    // accessors must change to fetch value from Ptr object
    int get_ptr_val() const { return *ptr; }
    int get_int() const { return val; }

    // change the appropriate data member
    void set_ptr(int *p) { ptr = p; }
    void set_int(int i) { val = i; }

    // return or change the value pointed to, so ok for const objects
    int *get_ptr() const { return ptr; }
    void set_ptr_val(int p) const { *ptr = p; }
  private:
    int *ptr;  // points to an int
    int val;
};

HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
  // Note: Every HasPtr is guaranteed to point at an actual int;
  // We know that ptr cannot be a zero pointer
  *ptr = *rhs.ptr;       // copy the value pointed to
  val = rhs.val;         // copy the int
  return *this;
}

int main()
{
  
  return 0;
}


// my test
#include <iostream>
#include <string>
using namespace std;

/*
* Valuelike behavior even though HasPtr has a pointer member:
* Each time we copy a HasPtr object, we make a new copy of the
* underlying int object to which ptr points.
*/
class HasPtr {
  public:
    HasPtr():ptr(new int(0)),val(0){} // 如果木有参数

    // no point to passing a pointer if we're going to copy it anyway
    // store pointer to a copy of the object we're given
    HasPtr(const int &p, int i): ptr(new int(p)), val(i) {}
    // new int(p):在堆中申请一个内存,存放整数p。返回申请到的内存指针

    // copy members and increment the use count
    HasPtr(const HasPtr &orig):
      ptr(new int (*orig.ptr)), val(orig.val) {}

    HasPtr& operator=(const HasPtr&);
    ~HasPtr() { delete ptr; }
    // accessors must change to fetch value from Ptr object
    int get_ptr_val() const { return *ptr; }
    int get_int() const { return val; }

    // change the appropriate data member
    void set_ptr(int *p) { ptr = p; }
    void set_int(int i) { val = i; }

    // return or change the value pointed to, so ok for const objects
    int *get_ptr() const { return ptr; }
    void set_ptr_val(int p) const { *ptr = p; }
  private:
    int *ptr;  // points to an int
    int val;
};

HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
  // Note: Every HasPtr is guaranteed to point at an actual int;
  // We know that ptr cannot be a zero pointer
  *ptr = *rhs.ptr;       // copy the value pointed to
  val = rhs.val;         // copy the int
  return *this;
}


int main()
{
  int *pi = new int(1024);  // object to which pi points is 1024
  cout << *pi << endl << endl;
  delete pi;
  
  HasPtr ptra(2,3);
  cout << ptra.get_ptr_val() << endl;
  cout << ptra.get_int() << endl << endl;
  
  HasPtr ptrb;
  ptrb=ptra;
  cout << ptrb.get_ptr_val() << endl;
  cout << ptrb.get_int() << endl << endl;  
  
  int n(5);
  ptrb.set_ptr(&n);
  ptrb.set_int(8);
  cout << ptrb.get_ptr_val() << endl;
  cout << ptrb.get_int() << endl;   
  
  return 0;
}

 

 

 

 

TOP

 

posted on 2014-11-10 20:18  欣乐  阅读(164)  评论(0编辑  收藏  举报