zoukankan      html  css  js  c++  java
  • 【C++ Primer 第13章】1. 拷贝控制、赋值和销毁

    拷贝控制、赋值和销毁

    • 如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数(拷贝构造函数不应该是explicit的)。
    • 如果我们没有为一个类定义拷贝构造函数,编译器会为我们定义一个,与合成默认构造函数不同, 即使我们定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数。
     1 class Sales_data
     2 {
     3 public:
     4     Sales_data(const Sales_data&);
     5 private:
     6     string bookNo;
     7     int units_sold = 0;
     8     double revenue = 0.0;
     9 };
    10  
    11 Sales_data::Sales_data(const Sales_data &rhs):
    12 bookNo(rhs.bookNo),       //ISBN号
    13 units_sold(rhs.units_sold), //销量
    14 revenue(rhs.revenue) //总销售收入
    15 {}

      

     析构函数

    • 当一个类定义自己的析构函数时,编译器会为它定义一个合成析构函数。

     练习参考答案

    13.13

     1 #include<iostream>
     2 #include<string>
     3 #include<vector>
     4 using namespace std;
     5  
     6 struct X
     7 {
     8     X() { cout << "默认构造函数X()" << endl; }
     9     X(const X&) { cout << "拷贝构造函数 X(const X&)" << endl; }
    10     X& operator=(const X &rhs) { cout << "拷贝赋值运算符=(const X&)" << endl; return *this; }
    11     ~X() { cout << "析构函数 ~()" << endl; }
    12 };
    13  
    14 void f1(X x)
    15 {}
    16  
    17 void f2(X &x)
    18 {}
    19  
    20 int main()
    21 {
    22     cout << "局部变量" << endl;
    23     X x;
    24     cout << endl;
    25  
    26     cout << "非引用参数传递:" << endl;
    27     f1(x);
    28     cout << endl;
    29  
    30     cout << "引用参数传递" << endl;
    31     f2(x);
    32     cout << endl;
    33  
    34     cout << "动态内存:" << endl;
    35     X *px = new X(x);
    36     cout << endl;
    37  
    38     cout << "添加到容器中:" << endl;
    39     vector<X> vx;
    40     vx.push_back(x);
    41     cout << endl;
    42  
    43     cout << "释放动态内存" << endl;
    44     delete px;
    45     cout << endl;
    46  
    47     cout << "间接初始化和赋值:" << endl;
    48     X y = x;
    49     y = x;
    50     cout << endl;
    51  
    52     cout << "程序结束" << endl;
    53     return 0;
    54 }

    运行结果:


      

    三五法则

    •  如果一个类需要自定义析构函数,几乎可以肯定它也需要自定义拷贝赋值运算符和拷贝构造函数。
    •  如果一个人类需要一个拷贝构造函数,几乎可以肯定它也需要一个拷贝赋值运算符。
    •  如果一个类需要一个拷贝赋值运算符,几乎可以肯定它也需要一个拷贝构造函数。

     练习参考答案

    //13.14: 0 0 0
    
    //13.15: 3 4 5
    
    //13.16: 0 1 2
    
    #include<iostream>
    using namespace std;
    
    class numbered
    {
    private:
    	static int seq;
    public:
    	numbered() { mysn = seq++; }
    	numbered(numbered &n) { mysn = seq++; }
    	int mysn;
    };
    
    int numbered::seq = 0;
    
    void f(numbered s)
    {
    	cout << s.mysn << endl;
    }
    
    int main(int argc, char **argv)
    {
    	numbered a, b = a, c = b;
    	f(a);
    	f(b);
    	f(c);
    	return 0;
    }
    

     

    使用=default

    • 我们可以通过将拷贝控制成员定义为=default来显式地要求编译器生成合成的版本。
    class Sales_data 
    {
    public:
        //拷贝控制成员; 使用default
        Sales_data() = default;
        Sales_data(const Sales_data &) = default;
        Sales_data& operator=(const Sales_data &);
        ~Sales_data() {} = default;
        //其他成员的定义,如前
    }
    Sales_data& Sales_data::operator=(const Sales_data &) = default;
    

    阻止拷贝

    如果一个类有数据成员不能默认构造、拷贝、复制和销毁,则对应的成员函数将被定义为删除的。规则引申如下:

    • 如果类的某个成员的析构函数时删除的或不可访问的,则类的合成析构函数被定义为删除的;同时类的默认构造函数是删除的;同时类的合成拷贝构造函数也被定义为删除的。(析构函数被定义为删除的,则不能定义该类型的变量。)
    • 如果类的某个成员的拷贝构造函数是删除的或不可访问的,则类的合成拷贝构造函数被定义为删除的;
    • 如果类的某个成员的拷贝赋值运算符是删除的或不可访问的,或类有一个const的或引用成员,则类的合成拷贝赋值运算符被定义为删除的;
    • 如果类有一个引用成员,它没有类内初始化器,或是类有一个const成员,没有类内初始化器且其类型未显式定义默认构造函数,则该类的默认构造函数是删除的。

     练习参考答案

    【练习13.5】

    1 class HasPtr
    2 {
    3 public:
    4     HasPtr(const string &s = string()): ps(new string(s)), i(0) {}
    5     HasPtr(const HasPtr &rhs): ps( new string(*rhs.ps)), i(rhs.i) {}
    6 private:
    7     string *ps;
    8     int i;
    9 }

     【练习13.8】

     1 class HasPtr
     2 {
     3 public:
     4     HasPtr(const string &s = string()): ps(new string(s)), i(0) {}
     5     HasPtr(const HasPtr &rhs): ps( new string(*rhs.ps)), i(rhs.i) {}
     6  
     7     HasPtr operator=(const HasPtr &rhs);
     8 private:
     9     string *ps;
    10     int i;
    11 }
    12  
    13 HasPtr HasPtr::operator=(const HasPtr &rhs)
    14 {
    15     ps = new string(*rhs.ps);
    16     i = rhs.i;
    17     return *this;
  • 相关阅读:
    编程是点滴的积累
    Tech.ED 2005 北京 第二天印象
    Tech.ED 2005 北京 第三天印象
    别把事情弄的太复杂
    在看《青衣》
    可以用的开源包
    KVM虚拟机的性能问题
    [zz]kvmlibvirt的使用:创建虚拟机与快照
    KVM快照snapshot
    [zz]kvm环境快照(snapshot)的使用方法
  • 原文地址:https://www.cnblogs.com/sunbines/p/8987279.html
Copyright © 2011-2022 走看看