复制构造函数和合成复制构造函数
- 复制构造函数
复制构造函数又称为拷贝构造函数,它是一种特殊的构造函数。它的作用就是用一个已经生成的对象来初始化另一个另一个同类的对象
变量的初始化:
int a=10;int b=a;
对象的初始化:
point pt1(10,20); point pt2 = pt1;
复制构造函数定义的一般形式为:
类名(const 类名&obj) {
函数体
}
例如:
class Point { //Point类
public:
Point() : x(0),y(0) { } //默认构造函数
Point(const Point& r) : (r.x),y(r.y) { } //复制构造函数
Point(int a,int b) : x(a),y(b) { } //带参数构造函数
private:
int ,x,y;
};
复制构造函数有且只有一个本类类型对象的引用形参,**通常使用const限定。**因为复制构造函数只是复制对象,没有必要改变传递来的对象的值
复制构造函数的功能是利用一个已知的对象来初始化一个被创建的同类的对象
与复制构造函数对应的对象定义形式为:
类名 对象名1(类对象),对象名2(类对象2),....;
对象赋值和对象复制的区别:
对象的赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值
对象的复制是从无到有地建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值)
- 合成复制构造函数
每个类必须有一个复制构造函数。如果类没有定义复制构造函数,编译器就会自动合成一个,称为合成复制构造函数(synthesized copy constructor)
与合成默认构造函数不同,即使定义了其他构造函数,编译器,也会合成复制构造函数
合成复制构造函数的操作是:执行逐个成员初始化,将新对象初始化为原对象的副本
所谓”逐个成员",指的是编译器将现对象的每个非静态数据成员,依次复制到正创建的对象中。每个成员的类型决定了复制该成员的含义:
(1)内置类型成员直接复制其值
(2)类类型成员使用该类的复制构造函数进行复制
(3)如果一个类具有数组成员,则合成复制构造函数将复制数组,即复制数组的每一个元素到新对象中
逐个成员初始化可以这样理解:将合成复制构造函数看作是每一个数据成员在构造函数初始化列表中进行初始化的构造函数
以下3种情况会使用复制构造函数
- 用一个对象显式或隐式初始另一个对象
C++支持两种初始化形式:复制初始化和直接初始化。复制初始化使用等号(=),而直接初始化将初始化式放在圆括号中
复制初始化和直接初始化是有区别的:直接初始化会调用与实参匹配的构造函数;而复制初始化总是调用复制构造函数
Point pt1(10,20);
Point pt2=pt1; //复制初始化
Point pt3(pt1); //直接初始化
-
函数参数按值传递对象时或函数返回对象时
当函数形参为对象类型,而非指针和引用类型时,函数调用按值传递对象,即编译器调用复制函数产生一个实参对象副本传递到函数中
类似地,以对象类型作为返回值时,编译器调用复制构造函数产生一个return语句中的值的副本返回到调用函数 -
根据元素初始化式列表初始化数组元素时
如果没有为类类型数组提供元素初始化式,则将用默认构造函数初 始化每个元素。然而,如果使用常规的大括号的数组初值列表形式 来初始化数组时,则使用复制初始化来初始化每个元素
总的来说,正是有了复制构造函数,函数才可以传递对象和返回对象,对象数组才能用初值列表的形式初始化
深复制与浅复制
如果一个拥有资源(如用new得到的动态内存)的类对象发生复制的时候,若对象数据与资源内容一起复制,称为深复制,如图所示:
若复制对象但未复制资源内容称为浅复制,如图所示:
深复制,浅复制举例:
#include<iostream>
#include<string>
using namespace std;
class CA {
public:
CA(int b,char *cstr) { //构造函数
a=b;
str=new char[b];
strcpy(str,cstr);
}
CA(const CA &C) { //复制构造函数
a=C.a;
str=new char[a]; //深复制,浅复制则写成str=C.str
}
if(str!=0)
strcpy(str,C.str);
void show() {
cout<<str<<endl;
~CA() { //析构函数
delete str;
}
private:
int a;char *str;
};
int main()
{
CA a(10,"hello");
CA b=a;
b.show();
return 0;
}