首页 > 代码库 > c++OOP之复制控制 ------复制构造函数、赋值重载、析构

c++OOP之复制控制 ------复制构造函数、赋值重载、析构

本博文我们讨论OOP复制控制的一些内容;

首先考虑对象复制的时机: 非引用类型

1):根据一个类去显式或者隐式初始化一个对象;

2):复制一个对象,将它作为实参传给一个函数;

3):从函数返回时复制一个对象。(string tolittle(string word))

一个空类,编译器提供默认无参数构造函数、拷贝构造函数、赋值运算符以及析构函数,一共四个函数。(面试)
11.复制构造函数、赋值运算符以及析构函数,称为三法则,一旦提供了其中一个,务必提供其余两个。以String为例:a)  涉及到深拷贝、浅拷贝问题,所以需要提供拷贝构造函数b)  然后,为了保持一致,赋值运算符也应该实现深拷贝c)  既然实现深拷贝,那么必定申请了资源(例如内存),所以必然需要析构函数来手工释放。

 一:复制构造函数:

复制构造函数调用的时机就是在对象复制的时候。方式有两种:

1):当用户不提供时,编译器自动为我们合成一个拷贝构造函数;

示例代码如下:

#include <iostream>#include <string>using namespace std;class Student {    public:        Student()        {}        Student(int id, const string&name, int age)            :id_(id),name_(name),age_(age)        {}                void print()        {  cout << id_ <<":" << name_ <<":" << age_ << endl; }    private:        int id_;        string name_;        int age_;};int main(int argc, const char *argv[]){    Student s(11,"zhangsan",23);    s.print();    Student s2(s); //执行此句,调用默认复制构造函数    s2.print();    return 0;}

 2):用户自己定义:

放入class Student 的public中即可;

1   Student(const Student &s)2         {3             id_ = s.id_;4             name_ = s.name_;5             age_ = s.age_;6         }

复制构造函数之 深copy 和 浅copy;

含有指针成员变量的类在复制时,有两种选择:a) 复制指针的值,这样复制完毕后,两个对象指向同一块资源,这叫做浅拷贝 shallow copy(有可能出错)b) 复制指针所指向的资源,复制完毕后,两个对象各自拥有自己的资源,这叫做深拷贝 deep copy

 示例代码:

 1 #include "iostream" 2 #include "string.h" 3 using namespace std; 4  5 //copy String 时,仅仅复制指针的值 6 //导致析构时发生了问题 7 class String 8 { 9     public:10         String();11         String(const char*s);12         String(const String &s);13         ~String();       14         void print()const15         {16             cout << str_ << endl;17         }18     private:19         char *str_;20 };21 String::String()22     :str_(new char(0))23 {  }24 String::String(const char *s)25     :str_(new char[strlen(s)] +1)26 {27     ::strcpy(str_, s);28 }29 //程序结束时会调用析构函数,两个对象s1,s2必然会析构两次,而str_指向同一片区域;30 //当析构s1时,s1.str_所指向的区域被释放;而s2.str_ 也同时被释放31 //当析构s2时,由于s2.str_已经被s1.str_释放,所以会产生错误.32 String::String(const String &s)33     :str_(s.str_)34 {}35 36 /* 修改成以下即可:37  *String::String(const String &s)38  *     :str_(new char[strlen(s)] +1)39  * {40  *  ::strcpy(str_, s.str_);41  *  }42  */43 String::~String()44 {45     delete[] str_; //注意46 }47 int main(int argc, const char *argv[])48 {49     String s("helloworld");50     s.print();51     52     String s2(s);53     s.print();54     return 0;55 }

二: 赋值运算符的重载:【因为我们自定义的类没有内置比较运算符(<、>、!=)】
示例代码如下:

 1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4  5 class String 6 { 7     public: 8         String(); 9         String(const char *s);10         String(const String &s);11         ~String();12         String &operator = (const String &s);13         size_t size()const //自己构造size函数14         {15             return strlen(str_);16         }17         18         void print()19         { cout << str_ << endl; }20     private:21        char *str_;22 };23 String::String()24     :str_(new char[1])25 { *str_ = 0; }26 27 String::String(const char*s)28     :str_(new char(strlen(s)+1))29 { ::strcpy(str_, s); }30 31 String::String(const String &s)32     :str_(new char(strlen(s.str_)+1))33 { ::strcpy(str_, s.str_); }34 35 String &String::operator = (const String &s)36 {37    if(this == &s)//自身赋值38         return *this;39     delete[]str_;40     str_ = new char(s.size() + 1 );41     ::strcpy(str_, s.str_);42     43     return *this;44 }45 46 String::~String()47 { delete[] str_; }48 49 int main(int argc, const char *argv[])50 {51     String s("helle");52     s.print();53     54     String s2;55     s2 = s; //赋值重载56     s2.print();57     58     s2 = s2 ; //注意自身赋值情形59     s2.print();60     61     return 0;62 }

禁止类复制和赋值的方法:

a):把 copy构造函数和复制运算符设为private;

b):只声明,不实现;

 1 #include <iostream> 2 #include <string> 3 #include <vector> 4 using namespace std; 5  6 //no copy,no assignment 7 //google 推荐写法 8 #define   DISALLOW_COPY_AND_ASSIGN(TypeName)  9             TypeName(const TypeName&); 10                 void operator=(const TypeName&)11 12 class Test13 {14     public:15         Test(){}16         ~Test(){}17 18     private:19         Test(const Test&t);20         void operator=(const Test &t);21 };22 23 int main(int argc, const char *argv[])24 {25     Test t;26     27     Test t2(t);//error28 29     Test t3;30     t3 = t; //error31     32     return 0;33 }
a):如果一个类,不需要复制和赋值,那就禁用这种能力,这可以帮助避免大量潜在的bug。b):如果一个类,实现了像value一样的复制和赋值能力(意味着复制和赋值后,两个对象没有任何关联,或者逻辑上看起来无任何关联),那么就称这个类的对象为值语义(value semantics)。如果类不能复制,或者复制后对象之间的资源归属纠缠不清,那么称为对象语义(object semantics),或者引用语义(reference semantics)。

 

c++OOP之复制控制 ------复制构造函数、赋值重载、析构