copy构造函数

copy构造函数定义

copy构造函数的定义:如果一个构造函数的第一个参数是自身类类型的引用,且额外参数都是默认值,则此构造函数时copy构造函数(摘自c++primer)。

class Foo
{
 public:
    Foo();
    Foo(const Foo&);  //copy构造函数
}

copy构造函数的形参必须引用类型:如果不是引用类型,为了调用copy构造函数,必须copy他的实参,但copy实参又需要copy构造函数,一直循环。

copy构造函数何时发生:

1.显示地以一个对象的内容作为另一个类对象的初值(以"="的形式或者"()")

2.对象作为一个实参传递给一个非引用类型的形参

3.对象作为一个函数的返回值,返回类型为非引用类型

4.用花括号列表初始化一个数组中的元素或一个聚合类的成员

下面的例子验证以上四点(第三点似乎有些编译器优化了结果)

 1 class AA
 2 {
 3     public:
 4     AA(){cout<<"default"<<endl;}
 5 //    private:
 6     AA(const AA&){cout<<"copy"<<endl;}
 7     public:
 8         int a;
 9 };
10
11 void f_re(AA&a)
12 {
13
14 }
15
16 void f_nore(AA a)
17 {
18
19 }
20
21 AA& f_ret()
22 {
23     AA f;
24     return f;
25 }
26
27 int main()
28 {
29
30     AA a,b,c;
31     cout<<1<<endl;
32     AA m=a;
33     cout<<"2_re"<<endl;
34     f_re(a);
35     cout<<"2_nore"<<endl;
36     f_nore(a);
37     cout<<3<<endl;
38     f_ret();
39     cout<<4<<endl;
40     vector<AA> d{a,b,c};
41     return 0;
42 }

这是codeblock上编译的(),从编译结果看,

f_ret();

并没有产生copy构造函数,然后该在vs2013单独运行了

f_ret();

在这里copy构造函数是确实存在,我个人觉得应该是codeblock的编译优化了结果,所以我将试着把copy构造函数设为private,再次运行

1 class AA
2 {
3     public:
4     AA(){cout<<"default"<<endl;}
5     private:
6     AA(const AA&){cout<<"copy"<<endl;}   //设为private
7     public:
8         int a;
9 };

运行直接出错

所以,对象作为一个函数的返回值,返回类型为非引用类型需要copy构造函数是确定的。

还有一点就是花括号列表初始化数组,一个元素是调用copy构造函数两次的(这里我个人觉得可能用到了中间变量,具体原因我也没找出来)

区分直接初始化与copy初始化

一般来说使用等号(=)初始化一个变量,采用的是copy初始化,copy初始化一定用到copy构造(或者移动构造)

string s="hello"; //这个等价于两个操作 string temp("hello");string s=temp;

对于类类型的对象,拷贝初始化就相当于先创建一个对象(执行构造函数)再进行拷贝(执行拷贝构造函数)

直接初始化一般要求编译器使用普通的函数匹配来选择与之最匹配的构造函数(可以是构造函数也可以是copy构造函数)

string s1(s);  //copy构造

string s2("hello");  //构造函数

合成copy构造函数

一般来说如果一个类没有显式提供copy构造函数,编译器根据需要会提供一个合成的默认copy构造函数(这里一定要清楚是编译器觉得有必要才会生成)。

这个必要性由编译器有没有展现"bitwise copy semantic(位逐次copy)"来决定的。

只有在下面四种情况是不展现位逐次copy的,这个时候会逐个执行成员初始化,完成必要工作(合成copy构造):

1.当class内含一个成员对象,而这个成员对象声明了一个copy构造函数;

2.当class继承自一个基类,该基类存在一个copy构造函数;

3.当class声明了一个或多个虚函数;

4.当class派生自一个继承串链,其中有一个或多个数是虚基类。

所以当一个类没有显式的copy构造时,但采用位逐次copy时,会出现一个浅copy问题。

深拷贝与浅拷贝

深copy与浅copy主要在于copy的过程中,对资源处理的形式不同。

浅copy就是位逐次copy,直接将对象里成员的值赋值另一个对象,大多数情况下这是可以的,但是当成员对象存在资源(指针),这时他将指向同一个位置,这就存在一定的风险,当一个对象删除了,他的资源自然也就释放,但是另一个对象却还在,就会出现野指针了。

深copy则是重新开辟空间,存放资源,因而不存在不同对象指针指向同一个资源。

时间: 2024-12-08 08:51:24

copy构造函数的相关文章

正确地复制对象--oeprator=与copy构造函数

额,这个名字有点怪怪的=_= ok,下面进入正题,为了演示方便,代码只写出简略的部分. copy构造函数 class Base { public: Base() {} Base(const Base& ) { cout<<"Base copy "<<endl; } }; class Derived: public Base { public: Derived() {} Derived(const Derived& ind) {} }; 重点关注一

C++类禁止copy构造函数和copy assign操作符

C++类禁止copy构造函数和copy assign操作符 在C++类中,编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数.注意,这些编译器产生出来的函数都是public的,为了阻止这些函数被创建出来,我们可以把它们声明为private,这样就阻止了编译器暗自创建其对应版本函数. class Node { public: Node(int _data = 0) : data(_data) {} int get() cons

请为CMyString类型编写构造函数、copy构造函数、析构函数和赋值运算符函数。

如下为类型CMyString的声明,请为该类型编写构造函数.copy构造函数.析构函数和赋值运算符函数. 1 class CMyString 2 { 3 public: 4 CMyString(const char* pData = nullptr); 5 CMyString(const CMyString& str); 6 ~CMyString(void); 7 8 CMyString& operator = (const CMyString& str); 9 10 void P

【C/C++学院】(6)构造函数/析构函数/拷贝构造函数/深copy浅copy

1.构造函数 类的初始化即为构造函数.也为:隐式的初始化. 构造函数在对象初始化的时候,自动被调用.隐式的调用. 构造函数分为三种:有参构造函数.无参构造函数.拷贝构造函数. 有参构造函数调用有三种:括号法.等号法.手工法. #include <iostream> using namespace std; class Test { private: int m_a; public: Test()//无参构造函数 { } Test(const Test &obj)//拷贝构造函数 { }

(copy)赋值构造函数的4种调用时机or方法

第一种调用方法: demo #include <iostream> using namespace std; class Text { public: Text() // 无参数构造函数 { m_a = 0; m_b = 0; cout << "无参数构造函数" << endl; } Text(int a) // 有参数构造函数 { m_a = a; m_b = 0; cout << "无参数构造函数" <<

什么时候需要在类的构造函数中使用初始化列表

1,如果基类没有default构造函数,则意味着其不能自己初始化.如果其被派生,派生类的构造函数要负责调用基类的构造函数,并传递给它需要的参数.下例中Base 2,如果类成员没有默认构造函数.下例中Elem4 2,如果类的成员变量中含有const成员变量,如果不使用列表,在构造函数中是不能对其赋值的,会导致编译失败.下例中b 3,如果类的成员变量中含有引用,引用必须被初始化.下例中c 4,需要提高效率的时候,如果不使用初始化列表,而放在构造函数体内赋值的方法,则变量先被默认构造函数初始化,然后又

C++类对象的复制-拷贝构造函数

在学习这一章内容前我们已经学习过了类的构造函数和析构函数的相关知识,对于普通类型的对象来说,他们之间的复制是很简单的,例如: int a = 10; int b =a; 自己定义的类的对象同样是对象,谁也不能阻止我们用以下的方式进行复制,例如: #include <iostream>  using namespace std;    class Test  {  public:      Test(int temp)      {          p1=temp;      }  prote

c++中的构造函数和析构函数

构造函数:  C++提供了构造函数(constructor)来处理对象的初始化.在建立对象时自动执行.构造函数的名字必须与类名同名,它不具有任何类型,不返回任何值. 构造函数总结: ①构造函数是C++中用于初始化对象状态的特殊函数. ② 构造函数在对象创建时自动被调用(默认调用),隐身调用. ③构造函数和普通成员函数都遵循重载规则. ④拷贝构造函数是对象正确初始化的重要保证,必要的时候,必须手工编写拷贝构造函数. 构造函数的调用: 自动调用:一般情况下C++编译器会自动调用构造函数 手动调用:在

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

本博文我们讨论OOP复制控制的一些内容: 首先考虑对象复制的时机: 非引用类型 1):根据一个类去显式或者隐式初始化一个对象: 2):复制一个对象,将它作为实参传给一个函数: 3):从函数返回时复制一个对象.(string tolittle(string word)) 一个空类,编译器提供默认无参数构造函数.拷贝构造函数.赋值运算符以及析构函数,一共四个函数.(面试) 11.复制构造函数.赋值运算符以及析构函数,称为三法则,一旦提供了其中一个,务必提供其余两个.以String为例: a) 涉及到