第十三章 复制控制
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; }