学习笔记五:复制控制

来源:互联网 发布:网络平台怎么做 编辑:程序博客网 时间:2024/06/04 18:32

1.关键字explicit用于抑制由构造函数定义的隐式转换。
2.复制控制:复制构造函数、赋值操作和析构函数。
3.与默认构造函数不同,复制构造函数即使我们定义其他构造函数,系统仍会合成。合成复制构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。
4.只包含类类型或内置类型(但不是指针类型)成员的类,不需要显式地定义复制构造函数,它利用合成的复制构造函数也能完成复制操作。
5.有些类必须对复制对象发生的事情加以控制:(1)类有指针类型的数据成员,或有成员表示在构造函数分配的其他资源;(2)类在创建新对象时必须做一些特定工作。定义复制构造函数最困难的部分在于认识到需要复制构造函数。
6.为了防止复制,类必须显式声明其复制构造函数为private。然而,类的友元和成员仍可以进行复制。这是可以通过声明一个private复制构造函数而不对其定义,来达到禁止复制的目的。(声明而不定义成员函数是合法的)
7.不定义复制构造函数或默认构造函数,会严重影响类的使用。不允许复制的类对象只能作为引用传递给函数或者作为引用从函数中返回,而且它们不能作为容器的元素。
8.与复制构造函数一样,如果类没有定义自己的赋值操作符,编译器也会合成一个。
9.赋值操作符的返回类型应该与内置类型赋值运算返回的类型相同。内置类型的赋值运算返回对左操作数的引用,因此,赋值操作符也返回对同一类类型的引用。
示例:赋值操作符声明:

class Sales_item{public:    Sales_item& operator=(const Sales_item &);  };

10.合成赋值操作符:它与合成复制构造函数的操作类似。它会执行逐个成员赋值;右操作数对象的每个成员赋值给左操作数对象的对应成员。除数字之外,每个成员用所属类型的常规方式进行赋值。对于数组,给每个数组元素赋值。例如:

     // 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;     }

该操作符返回*this,它是对左操作数的引用。(在进行赋值操作之后,左值改变)
11.析构函数,可以完成所需的资源回收,它作为类构造函数的补充。
12.动态分配的对象只有在指向该对象的指针被删除时才撤销。如果没有删除指向动态对象的指针,则不会允许该对象的析构函数,对象就一直存在,从而导致内存泄露,而且,对象内部使用的任何资源也不会释放。(当对象的引用或指针超出作用域时,不会运行析构函数。)只有实际对象(而不是对象的引用)超出作用域时或删除指向动态分配对象的指针时,才会运行析构函数。——析构函数调用的时机
13.撤销内置类型成员或复合类型的成员没什么影响。但合成析构函数并不删除指针成员指向的对象。
14.虽然一个类可以定义多个构造函数,但(用户)最多只能提供一个析构函数,应用于类的所有对象。(当然,无论用户是否提供析构函数,编译器都会合成一个析构函数)
15.析构函数与复制构造函数或赋值操作符的一个重要区别是,即使我们编写了自己的析构函数,合成的析构函数仍然运行。
16.顺序容器(vector,list,deque)和set都支持复制构造函数。
17.顺序容器(vector,list,deque)和set都支持赋值构造函数。
验证set1:

    set<int> set1;    set1.insert(0);    set1.insert(1);    set<int> set2(set1),set3;    set3 = set1;    cout << "set1 = " << endl;    for(set<int>::iterator iter=set1.begin(); iter!=set1.end(); iter++)    {        cout << *iter << " ";    }    cout << endl;    cout << "set2 = " << endl;    for(set<int>::iterator iter=set2.begin(); iter!=set2.end(); iter++)    {        cout << *iter << " ";    }    cout << endl;    cout << "set3 = " << endl;    for(set<int>::iterator iter=set3.begin(); iter!=set3.end(); iter++)    {        cout << *iter << " ";    }    cout << endl;

验证list的赋值:

list<int> avec(10,1);list<int> bvec(9,0);cout << "bvec = " << endl;for(list<int>::iterator iter=bvec.begin(),int i=0 ; iter!=bvec.end(); iter++){    cout << *iter << " ";}cout << endl;bvec = avec;cout << "avec = " << endl;cout << "bvec = " << endl;for(list<int>::iterator iter=bvec.begin(); iter!=bvec.end(); iter++){    cout << *iter << " ";}

18.C++语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:
(1)元素类型必须支持赋值运算;
(2)元素类型的对象必须可以复制。
(原因:估计是容器模板的成员函数需要用到容器元素类型的复制和赋值,比如容器的push_back函数,其函数内部应该会有存在元素的赋值操作)
19.复制操作符通常要做复制构造函数和析构函数完成的工作。在这种情况下,我们可以把三者中通用的工作放在private实用函数中。
20.具有指针成员且使用默认合成复制构造函数的类具有普通指针的所有缺陷。尤其是,类本身无法避免悬垂指针。

0 0
原创粉丝点击