Contents
  1. 1. 什么是copy构造函数
  2. 2. copy构造函数的调用时机

什么是copy构造函数

首先对于普通的对象来说,他们之间的复制是很简单的,例如:

1
2
int a = 100;
int b = a;

但是类对象与普通的对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
一个empty class经过c++处理之后,就不再是简单的一个empty class。编译器会默默的帮你声明四个函数,都是public和inline类型。因此当你写下:
class empty(){};
就像写下了这样的代码:

1
2
3
4
5
6
7
8
9
10
class empty{
public:
**empty(){ ... }** //default 构造函数
**empty(const empty& rhs){ ... }** //copy构造函数
**~empty(){ ... }** //析构函数
**empty& operator=(const empty& rhs){ ... }** //copy assignment操作符
}

唯有这些函数被需要(被调用),他们才会被编译器创建出来。在程序中需要他们是很正常的事情。

empty e1; //default构造函数
empty e2(e1); //copy构造函数
e2 = e1; //copy assignment操作符

copy构造函数的调用时机

  • 对象以值传递的方式传入参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class CExample
{
private:
int a;
public:
//构造函数
CExample(int b)
{
a = b;
cout<<"creat: "<<a<<endl;
}
//拷贝构造
CExample(const CExample& C)
{
a = C.a;
cout<<"copy"<<endl;
}
//析构函数
~CExample()
{
cout<< "delete: "<<a<<endl;
}
void Show ()
{
cout<<a<<endl;
}
};
//全局函数,传入的是对象
void g_Fun(CExample C)
{
cout<<"test"<<endl;
}
int main()
{
CExample test(1);
//传入对象
g_Fun(test);
return 0;
}
  • test 对象传入形参时,先会产生一个临时变量,就暂时叫C吧。
  • 然后调佣构造函数把test的值给C。整个这两个步骤有点像:CExample C(test)
  • 等g_Fun()执行完后,析构C对象。
  • 对象以值传递的方式从函数返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class CExample
{
private:
int a;
public:
//构造函数
CExample(int b)
{
a = b;
}
//拷贝构造
CExample(const CExample& C)
{
a = C.a;
cout<<"copy"<<endl;
}
void Show ()
{
cout<<a<<endl;
}
};
//全局函数
CExample g_Fun()
{
CExample temp(0);
return temp;
}
int main()
{
g_Fun();
return 0;
}
  • 先会产生一个临时变量,就叫XXXX吧。
  • 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
  • 在函数执行到最后先析构temp局部变量.
  • 等g_Fun()执行完后再析构掉XXXX对象。
  • 对象需要通过另外一个对象进行初始化;
1
2
3
CExample A(100);
CExample B = A;
//CExample B(A);
  • 浅拷贝和深拷贝

    • 浅拷贝
      所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。
    • 如果你打算在一个”内含 reference 成员”的class内支持赋值操作,必须自己定义。
    • 面对”内含 const 成员”的classes, 编译器的反应是一样的。
    • 如果某个base class 将copy assignment操作符声明为 private,编译器拒绝为derived classes 生成一个copy assignment 操作符。

    • 深拷贝
      在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空。

    • 防止默认拷贝发生
      为驳回编译器自动(暗自)提供的功能,可将相应的成员函数声明为 private 并且不予实现。

  • 拷贝构造函数的几个细节

    • 拷贝构造函数里能调用private成员变量吗?
    • 这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时就是一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。

    • 以下函数哪个是拷贝构造函数,为什么?

1
2
3
4
X::X(const X&);
X::X(X);
X::X(const X&, int a = 5);
X::X(const X&, int a = 5, int b = 2);
  • 对于一个类X, 如果一个构造函数的第一个参数是下列之一:
    a) X&
    b) const X&
    c) volatile X&
    d) const volatile X&
    且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数. 所以第1,3,4都是拷贝构造函数。

    • 类中可以存在超过一个拷贝构造函数。

资料推荐:

[2]: effective c++


100days—第13天—013

Contents
  1. 1. 什么是copy构造函数
  2. 2. copy构造函数的调用时机