C++学习之复制构造函数


这篇文章是有关C++复制构造函数的学习内容。

构造函数

类的每个对象之间的区别有:外在区别为对象的名称,内在区别是对象自身的属性值,即数据成员的值。在定义对象的同时进行的数据成员设置,称为对象的初始化。

构造函数的作用就是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。构造函数也是一类成员函数,在对象被创建时将被自动调用。调用时无须提供参数的构造函数称为默认构造函数,类中没有写构造函数,编译器会自动生成一个隐含的默认构造函数,其参数列表和函数体皆为空。

构造函数可以直接访问类的所有数据成员,可以是内联函数(inline声明的函数),可以带有参数列表,可以带默认的形参值,可以重载。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Clock{
public:
Clock(int newH, int newM, int newS);//构造函数
Clock(){ //重载构造函数
hour = 0;
minute = 0;
second = 0;
}
void setTime(int newH, int newM, int newS);
void showTime();
}
//其他函数实现略
int main(){
Clock c1(0, 0, 0);//调用有参数的构造函数
Clock c2; //调用无参数的构造函数
...
}

复制构造函数

复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性,其形参是本类对象的引用。其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。

可以根据实际需要定义复制构造函数,以实现同类对象之间的数据成员的传递,如果不定义类的复制构造函数,系统会在必要时(需要使用复制构造函数时,如下三种情况)自动生成一个隐含的复制构造函数,其功能是将初始值对象的每个数据成员的值都复制到新建立的对象中。

复制构造函数被调用的情况:

    1. 当用类的一个对象去初始化该类的另一个对象时
    1. 当函数的形参是类的对象,调用函数时,进行形参和实参的结合时

    注意:只有把对象用值传递时,才会调用复制构造函数,如果传递引用,则不会调用复制构造函数,所以传递比较大的对象时,传递引用会比传递值的效率高很多。

    但是如果是值传递,在形参复制到实参会调用复制构造函数,如果允许复制构造函数传值,就会在复制构造函数内调用复制构造函数,形成永无休止的递归调用从而导致栈溢出。因此,C++的标准不允许复制构造函数传值参数,也就是只能传递引用(这样还可以避免无谓的消耗,提高代码的效率),在复制构造函数内部不会改变传入的对象的状态,所以可以使用常量引用。即ClassA(const ClassA& other)

    1. 当函数的返回值是类的对象,函数执行完成返回调用者时

    注意:由于在被调用函数内部定义的变量只在被调用函数作用域起作用,所以调用函数完成后,要返回的对象就会消亡。所以,这种情况系统会在主函数中创建一个无名临时对象,其生存期只在函数调用所处的表达式中。函数返回时会自动调用复制构造函数将返回值的值传给临时对象,使用临时对象完成赋值或输出等操作。

例子:

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
class Point{
public:
Point(int xx=0,int yy=0){ //构造函数
x=xx;
y=yy;
}
Point(const Point &p){ //复制构造函数,最好使用常量引用,不允许使用值传递的形式Point(Point p)
x=p.x;
y=p.y;
}
int getX(){return x;}
int getY(){return y;}
private:
int x,y;
}
void fun(Point p){
cout << p.getX()<<<endl;
}
Point g(){
Point a(1,2);
return a;
}
int main(){
Point a(1,2);
Point b(a); //1
Point c = a; //1
f(a); //2
Point x = g();//3
}

如果只是直接将原对象的数据成员值一一赋值给新对象的相应数据成员,其实没有必要再编写复制构造函数,只需使用隐含的默认构造函数足以。

但是,编写复制构造函数可以实现这样的操作,即在进行对象的复制时,只是有选择、有变化地进行复制。

另外,当类的数据成员中有指针类型时,默认复制构造函数实现的只能是浅复制,这会带来数据安全方面的隐患。要实现正确的复制,即深复制,必须编写复制构造函数。

  • 浅复制:用一个对象初始化另一个对象时,只复制了成员,并没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制。但是析构函数又在对象生命周期结束后释放资源,势必会两次返还资源,就会导致编译器报错。
  • 深复制:即当一个对象创建时,分配了资源,这时必须显示定义复制构造函数,这种在用一个对象初始化另一个对象时,不仅复制了成员,也复制了资源的复制方式称为深复制。

复制构造函数又被叫做拷贝构造函数(copy constructor),复制初始化也叫做拷贝初始化。

拷贝构造函数和拷贝初始化不要混淆。拷贝初始化过程要调用拷贝构造函数,但拷贝构造函数也可以用在直接初始化过程。

详情参见:explicit关键字、构造函数与对象初始化

本文标题:C++学习之复制构造函数

文章作者:阿翔

发布时间:2018年04月16日 - 18:04

最后更新:2019年05月28日 - 21:05

原始链接:http://ttshun.com/2018/04/16/C++学习之复制构造函数/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

点击给我一些鼓励叭!
-------------本文结束感谢您的阅读-------------
0%