拷贝构造函数
一,定义:
拷贝构造函数:在定义语句中用
同类型的对象初始化另一个对象。
二,格式
用类类型本身作形式参数。
该参数传递方式为按引用传递,避免在函数调用过程中生成形参副本。该形参声明为const,以确保在拷贝构造函数中不修改实参的值
C::C(const C& obj);
例子:
class
Cstudent
{
public
:
Cstudent(
string
string1
,
string
string2
,
int
t
)
:name(
string1
),school(
string2
), tele(
t
)
{
cout
<<
"construct a lei"
<<
endl;
}
~Cstudent()
{
cout
<<
"destroy"
<<
endl;
}
Cstudent()
{
cout
<<
"construct an empty lei"
<<
endl;
}
Cstudent(
const
Cstudent
&
t1
)
{
cout
<<
"copy"
<<
endl;
this
->name
=
t1
.name;
this
->school
=
t1
.school;
this
->tele =
t1
.tele;
}
string
name;
string
school;
int
tele;
};
int
main()
{
Cstudent
C1(
"wanger"
,
"yizhong"
, 2341);
Cstudent
C2=
Cstudent
(C1);
cout
<<
C2.name
<<
endl;
cout
<<
C2.school
<<
endl;
cout
<<
C2.tele
<<
endl;
Cstudent
C3(C1);
cout
<<
C3.name
<<
endl;
cout
<<
C3.school
<<
endl;
cout
<<
C3.tele
<<
endl;
Cstudent
C4 = C1;
cout
<<
C4.name
<<
endl;
cout
<<
C4.school
<<
endl;
cout
<<
C4.tele
<<
endl;
Cstudent
C5 =
Cstudent
(
Cstudent
(
"wanger"
,
"yizhong"
, 2341));
cout
<<
C5.name
<<
endl;
cout
<<
C5.school
<<
endl;
cout
<<
C5.tele
<<
endl;
return
0;
}
1.调用Cstudent的拷贝构造函数用对象obja初始化对象objb。如果有为Cstudent类明确定义拷贝构造函数,将调用这个拷贝构造函数,并且编译器不会再生成默认拷贝函数;如果没有为Cstudent类定义拷贝构造函数,将调用默认拷贝构造函数。
2.
Cstudent
C2=
Cstudent
(C1);
Cstudent
C3(C1);
Cstudent
C4 = C1;
--三者等价,只调用了拷贝构造函数,就完成了对象的创建与赋值。
特别地
-
Cstudent C5 = Cstudent ( Cstudent ( "wanger" , "yizhong" , 2341));中的 Cstudent ( "wanger" , "yizhong" , 2341)调用了有参数的构造函数,但是它没有调用析构函数,没有销毁,若该过程创建了动态内存,要手动释放。没有调用拷贝构造函数,=是指按位复制,是浅复制。
-
Cstudent C4=C1;与1.Cstudent C4;C4=Ctudent(C1)和2. Cstudent C4;C4=C1 不等价
1.
C4=Ctudent(C1)先调用了拷贝构造函数,再调用了=操作符
2.
C4=C1只
调用了=操作符
3.销毁顺序:C5,C4,C3,C2,C1
三,拷贝构造函数的触发
1.声明 C x(c) 或 new C(c) 会触发复制构造
2.
将一个对象作为实参,以按值调用方式传递给被调函数的形参对象。
假定C为已定义的类,obja为C类对象,且
void fun(C temp)
{ …
}
fun(obja)
-
obja传递给fun函数,创建形参对象temp时,调用C的拷贝构造函数用对象obja初始化对象temp,temp生存期结束被撤销时, 调用析构函数
-
若参数是C& tmp,则不会触发拷贝构造函数和析构函数,而是为obja,取别名tmp;
class
Cstudent
{
public
:
Cstudent(
string
string1
,
string
string2
,
int
t
)
:name(
string1
),school(
string2
), tele(
t
)
{
cout
<<
"construct a lei"
<<
endl;
}
~Cstudent()
{
cout
<<
"destroy"
<<
endl;
}
Cstudent()
{
cout
<<
"construct an empty lei"
<<
endl;
name
=
"\0"
;
school
=
"\0"
;
tele = 0;
}
Cstudent(
const
Cstudent
&
t1
)
{
cout
<<
"copy"
<<
endl;
this
->name
=
t1
.name;
this
->school
=
t1
.school;
this
->tele =
t1
.tele;
}
string
name;
string
school;
int
tele;
void
print(
Cstudent
&
another
)
{
cout
<<
another
.name
<<
endl;
another
.name
=
"zhangjiaxin"
;
}
};
int
main()
{
Cstudent
C1(
"wanger"
,
"yizhong"
, 2341);
Cstudent
C2=
Cstudent
(C1);
C1.print(C2);
return
0;
}
输出:
3.(旧版)生成一个临时对象作为函数的返回结果:当函数返回一对象时,系统将自动创建一个临时对象来保存函数的返回值。创建此临时对象时调用拷贝构造函数,当函数调用表达式结束后,撤销该临时对象时,调用析构函数。
(新版优化)但现在的gcc/g++不这么处理,会做一个优化。在Cstudent函数里有个c变量,离开func时不
撤销这个对象,而是让new C和这个对象关联起来(
但是不需要手动释放return c中c的内存
)。也就是说tmp的地址和new C是一样的。
class
Cstudent
{
public
:
Cstudent(
string
string1
,
string
string2
,
int
t
)
:name(
string1
),school(
string2
), tele(
t
)
{
cout
<<
"construct a lei"
<<
endl;
}
~Cstudent()
{
cout
<<
"destroy"
<<
endl;
}
Cstudent()
{
cout
<<
"construct an empty lei"
<<
endl;
name
=
"\0"
;
school
=
"\0"
;
tele = 0;
}
Cstudent(
const
Cstudent
&
t1
)
{
cout
<<
"copy"
<<
endl;
this
->name
=
t1
.name;
this
->school
=
t1
.school;
this
->tele =
t1
.tele;
}
string
name;
string
school;
int
tele;
Cstudent
setup()
{
Cstudent
c(
"zhangjiaxin"
,
"sysu"
, 19);
//只调用了构造函数
//如果传c的地址,并用Cstudent* c1接收,则起不到复制效果,c1指向的空间为空。
Cstudent a
(
"zhangjiaxin"
,
"sysu"
, 29);//
调用了析构函数和构造函数
return
c;//a在这里调用析构函数,c不调用析构函数
}
};
int
main()
{
Cstudent
C1(
"wanger"
,
"yizhong"
, 2341);
Cstudent
C2=
Cstudent
(C1);
Cstudent
c = C1.setup();
//Cstudent c没有调用构造函数和拷贝构造函数,代码中的=是按位复制,依旧是浅复制;
Cstudent
c1( C1.setup());
Cstudent c没有调用拷贝构造函数,
代码中的=是按位复制,
只进行了浅复制。
cout
<<
c1.name
<<
endl;
return
0;
}
四,拷贝构造函数自定义
1. 对于
不含指针成员的类,使用系统提供(编译器合成)的默认拷贝构造函数即可。
2. 缺省(默认)拷贝构造函数使用
浅复制策略,不能满足对含指针数据成员的类需要。
3. 含指针成员的类通常应重写以下内容:
• 构造函数(及拷贝构造函数)中分配内存,深复制策略
• = 操作重写,完成对象深复制策略
• 析构函数中释放内存
浅拷贝
只复制成员指针的值,而不复制指向的对象实体,导致新旧对象成员指针指向
同一块内存。但深拷贝要求成员指针指向的对象也要复制,新对象跟原对象的成员指针
不会指向同一块内存,
修改新对象不会改到原对象。