手机版
你好,游客 登录 注册
背景:
阅读新闻

C++复制控制:拷贝构造函数

[日期:2015-02-15] 来源:Linux社区  作者:mengwang [字体: ]

一、拷贝构造函数是一种特殊构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。与默认构造函数一样 ,拷贝构造函数可由编译器隐式调用。拷贝构造函数应用的场合为:

(1)根据另一个同类型的对象显式或隐式初始化一个对象。

(2)复制一个对象将它作为实参传给一个函数。

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

(4)初始化顺序容器中的元素。

(5)根据元素初始化式列表初始化数组元素。

下面分别对以上5点进行说明。

1、对象的定义式。

C++支持两种初始化形式:直接初始化和复制初始化。复制初始化使用“=”符号,而直接初始化将初始化式放在圆括号中。对于类类型对象,初始化的复制形式和直接形式有所不同。

直接初始化直接调用与实参匹配的构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用拷贝构造函数将那个临时对象复制到正在创建的对象。

string null_book = "9-999-99999-9";        // copy-initialization   
string dots(10, '.');                    // direct-initialization   

string empty_copy = string();            // copy-initialization   
string empty_direct;                    // direct-initialization 

说明:

(1)对于类类型对象,只有指定单个实参或显式创建一个临时对象用于复制时,才使用复制初始化。

(2)支持初始化的复制形式主要是为了与C的用法兼容。当情况许可时,可以允许编译器跳过复制构造函数直接创建对象,但编译器没有义务这样做。

(3)对于不支持复制的类型,或者使用explicit构造函数,不能进行复制初始化。例如:由于不能复制IO类型的对象,所以不能对那些类型的对象使用复制初始化。

ifstream file1("filename");                // ok: direct initialization 
ifstream file2 = "filename";            // error: copy constructor is private 
// This initialization is okay only if the Sales_item(const string&) constructor is not explicit 
Sales_item item = string("9-999-99999-9"); 

2、形参与返回值。

当形参为非引用类型时,将复制实参的值,以非引用类型作返回值时,将返回return语句中值的副本。因而,当形参或返回值为类类型时,由拷贝构造函数进行复制。

string make_plural(size_t, const string &, const string &);

这个函数隐式使用string拷贝构造函数返回值的副本,形参是const引用,不会复制。

3、初始化容器元素。

vector<string> vec(5);

使用了默认构造函数和拷贝构造函数。编译器首先使用string默认构造函数创建一个临时对象,然后使用拷贝构造函数将临时值复制到vec的每个元素。

4、构造函数与数组元素。

当用花括号初始化列表来显式初始化类类型的数组,则使用复制初始化来初始化每个元素。根据指定值创建适当类型元素,然后用拷贝构造函数将该值复制到相应元素。

Sales_item primer_eds[] = { string("0-201-16487-6"),
                            string("0-201-54848-8"),
                            string("0-201-82470-1"),
                            Sales_item()
                            };

当定义一个新对象并用一个同类型的对象对它初始化时,将显式使用拷贝构造函数。当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用拷贝构造函数。

二、合成的拷贝构造函数。

如果没有定义拷贝构造函数,编译器就会为我们合成一个。与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成拷贝构造函数。合成拷贝构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。

说明:

(1)编译器将现在对象的每个非static成员,依次复制到正创建的对象。每个成员的类型决定了复制该成员的含义。

(2)合成拷贝构造函数直接复制内置类型成员的值,类类型成员使用该类的拷贝构造函数进行复制。

(3)数组成员的复制是个例外。虽然一般不能复制数组,但如果一个类具有数组成员,则合成复制构造函数将复制数组的每一个元素。

Sales_item::Sales_item(const Sales_item &orig):
isbn(orig.isbn),                //使用string拷贝构造函数
units_sold(orig.units_sold),    //直接复制orig.units_sold
revenue(orig.revenue)            //直接复制orig.revenue
{ }

三、定义自己的拷贝构造函数。

拷贝构造函数就是接受单个类类型引用形参(通常用const修饰)的构造函数。因为用于向函数传递对象和从函数返回对象,该构造函数一般不应设置为explicit,拷贝构造函数应将实参的成员复制到正在构造的对象。它与类同名,没有返回值,可以(而且应该)使用构造函数初始化列表初始化新创建对象的成员,可以在函数体中做任何其他必要工作。

说明:

(1)合成拷贝构造函数只完成必要的工作。只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数,也可以复制。

(2)有些类必须定义复制构造函数对复制对象时发生的事情加以控制。例如:

1)类有一个数据成员是指针,或者有成员表示在构造函数中分配的其他资源

2)类在创建新对象时必须做一些特定工作。

四、禁止复制。

有些类需要完全禁止复制,例如:iostream。如何禁止复制呢?省略拷贝构造函数这种做法不行,因为编译器将会帮我们合成一个。为了防止复制,类必须显式声明其拷贝构造函数为private。

说明:

(1)如果拷贝构造函数是私有的,将不允许用户复制该类型对象。

(2)类的友元和成员仍可以进行复制,如果也想禁止它们,可声明一个私有的拷贝构造函数但不对其定义。声明而不定义是合法的,但使用未定义的成员将导致链接失败。

(3)通过声明不定义私有拷贝构造函数,可禁止任何复制类类型对象的尝试:用户尝试复制导致编译错误,成员函数和友元复制导致链接错误。

(4)如果定义了拷贝构造函数,也必须定义默认构造函数。不允许复制的类对象只能作为引用传递给函数或从函数返回,它们也不能作为容器元素,严重局限类的使用。

------------------------------分割线------------------------------

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码 http://www.linuxidc.com/Linux/2014-05/101227.htm

读C++ Primer 之构造函数陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

读C++ Primer 之智能指针 http://www.linuxidc.com/Linux/2011-08/40177.htm

读C++ Primer 之句柄类 http://www.linuxidc.com/Linux/2011-08/40175.htm

C语言梳理一下,分布在以下10个章节中:

  1. Linux-C成长之路(一):Linux下C编程概要 http://www.linuxidc.com/Linux/2014-05/101242.htm
  2. Linux-C成长之路(二):基本数据类型 http://www.linuxidc.com/Linux/2014-05/101242p2.htm
  3. Linux-C成长之路(三):基本IO函数操作 http://www.linuxidc.com/Linux/2014-05/101242p3.htm
  4. Linux-C成长之路(四):运算符 http://www.linuxidc.com/Linux/2014-05/101242p4.htm
  5. Linux-C成长之路(五):控制流 http://www.linuxidc.com/Linux/2014-05/101242p5.htm
  6. Linux-C成长之路(六):函数要义 http://www.linuxidc.com/Linux/2014-05/101242p6.htm
  7. Linux-C成长之路(七):数组与指针 http://www.linuxidc.com/Linux/2014-05/101242p7.htm
  8. Linux-C成长之路(八):存储类,动态内存 http://www.linuxidc.com/Linux/2014-05/101242p8.htm
  9. Linux-C成长之路(九):复合数据类型 http://www.linuxidc.com/Linux/2014-05/101242p9.htm
  10. Linux-C成长之路(十):其他高级议题

本文永久更新链接地址http://www.linuxidc.com/Linux/2015-02/113457.htm

linux
相关资讯       C++  拷贝构造函数 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款