您的位置:首页 > 编程语言 > C语言/C++

C++之构造函数、拷贝构造函数、析构函数(节自《C++语言程序设计》第三版)

2017-03-28 23:19 239 查看

1、构造函数

要理解构造函数,首先需要理解对象的建立过程。

我们先来看看一个基本类型变量的初始化过程:每一个变量在程序运行时都要占据一定的内存空间,在声明一个变量时对变量进行初始化,就意味着在为变量分配内存单元的同时,在其中写入了变量的初始值。

这样的初始化在C++源程序中看似很简单,但是编译器却需要根据变量的类型自动产生一些代码来完成初始化工作。

对象的建立过程也是类似的:在程序执行过程中,当遇到对象声明语句时,程序会向操作系统申请一定的内存空间用于新建的对象。我们希望程序猿能像对待普通变量一样,在分配内存空间的同时将数据成员的初始值写入。

但是不幸的是,与普通变量相比,类的对象太复杂了,编译器不知道如何产生代码来实现初始化。因此如果需要对对象进行初始化,程序员就要编写初始化程序。如果程序员没有自己编写初始化程序,却在声明对象时贸然指定对象初始值,不仅不能实现初始化,还会引起编译时的语法错误。

尽管如此,C++编译系统还是在对象初始化问题上还是替我们做了很多工作,C++中严格规定了初始化程序的接口形式,并有一套自动的调用机制。这里所说的初始化程序,便是构造函数。

构造函数的作用就是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。构造函数除了具有一般成员函数的特征之外,还有一些特殊的性质:构造函数的函数名与类名相同,而且没有返回值。只要类中有了构造函数,编译器便会在建立新对象的地方自动插入对构造函数的调用代码。因此我们通常说构造函数在对象被创建时将被自动调用。

如果类中没有写构造函数,编译器会自动生成一个默认形式的构造函数——没有参数,也不做任何事情的构造函数。

既然编译器自动生成的构造函数不做任何事情,我们还要生成它呢?这是因为在建立对象时自动调用构造函数是C++程序“例行公事”的必然行为。

若在类中定义了构造函数,编译系统便不会再为其生成默认构造函数了。而自定义的构造函数如果带有形式参数,那么建立对象时就必须给出初始值,用来作为调用构造函数时的实参。如果不给出必要的实参,编译时就会指出语法错误。

所以一般我们会重载构造函数,为类写一个有参数的构造函数和一个无参数的构造函数。

另外值得注意的是,对象所占据的内存空间只是用于存放数据成员,函数成员不在每一个对象中存储副本。

2、拷贝构造函数

生成一个对象的副本有两种途径:

一是建立一个新对象,然后将已有对象的数据成员的值取出来,一一赋给新的对象。这样虽然可行,但不免繁琐。试想一个类的数据成员如果有很多个,程序涉及的建立对象副本的操作有很多,这样做将非常不便。我们何不使类具有自行复制本类对象的能力呢?这便是拷贝构造函数的功能。

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

程序员可以根据实际问题的需要定义特定的拷贝构造函数,以实现同类对象之间数据成员的传递。如果程序员没有定义类的拷贝构造函数,系统就会在必要时自动生成一个默认的拷贝构造函数。该默认拷贝构造函数的功能就是把初始值对象的每个数据成员的值都复制到新建立的对象中。这样,新建立的对象与原对象具有完全相同的数据成员。

普通构造函数是在对象创建时被调用,而拷贝构造函数是在以下三种情况使用:

1)当用类的一个对象去初始化类的另一个对象时,例如:

Point A(1,2);
Point B(A);//用对象A初始化对象B,拷贝构造函数被调用2)如果函数的形参是类的对象,调用函数时,进行形参和实参结合时,例如:
int main()
{
Point A(1, 2);
f(A);//函数的形参为类的对象,当调用函数时,拷贝构造函数被调用
}

3)如果函数的返回值是类的对象,函数执行完成返回调用者时,例如:
Point g()
{
Point A(1, 2);
return A;//函数的返回值是类对象,返回函数值时,调用拷贝构造函数
}
int main()
{
Point B;
B = g();
return 0;
}
为什么返回函数值时,会调用拷贝构造函数呢?表面上函数g将A返回给了主函数,但是A是g()的局部对象,离开建立它的函数g以后就消亡了。在处理这种情况时,编译系统会在主函数创建一个临时的无名对象,该临时对象的生存期只在函数调用所处的表达式中B=g()中。执行语句“return A”,实际上是调用拷贝构造函数将A的值拷贝到临时对象中。函数g运行结束时对象A消失,但临时对象会存在于表达式中B=g()中。计算完这个表达式后,临时对象的使命也就完成了,该临时对象便自动消失。
当类的成员函数中有指针类型时,默认的拷贝构造函数实现的只是浅拷贝,浅拷贝会带来数据安全方面的隐患,要实现正确的拷贝,也就是深拷贝,必须编写拷贝构造函数。关于深拷贝与浅拷贝的理解,请戳:

3、析构函数

析构函数用来完成对象被删除前的一些清理工作,是在对象的生存期即将结束的时刻被自动调用的。调用完成后,对象也就消失了,相应的内存空间也被释放。

析构函数不接受任何参数,名称是由类名前面加~,没有返回值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐