在之前已经大概介绍了类的概念,大家对类应该有了初步的了解,今天给大家介绍一个系统提供的六种函数,具体看前四种。

系统提供函数函数的特点:(1)公有的

                                            (2)内联的(无堆栈的开辟和清理,只是在函数调用点展开) 

一、构造函数

作用:初始化对象的内存地址空间,构造函数名与类名相同。

例子:有一个商品类,成员变量有商品名称、商品数量、商品价格。

面向对象(二)

如上图所示,有两个构造函数,一个是不带参数的构造函数,另一个是带三个参数的构造函数,当我们用类实例化对象时,就会调用对应的构造函数。

CGoods  good1;//调用不带参数的构造函数

CGoods  good2(“面包”,20,5.5);//调用带三个参数的构造函数

注意:1、构造函数可以重载,上图中所示,两个构造函数构成了函数重载。

           2、如果在类中有实现的构造函数,系统就不会调用默认的构造函数。如果没有,系统便会给出默认的构造函数。

           3、实例化对象:(1)分配对象的内存空间

                                       (2)调用对象的构造函数

二、析构函数

作用:释放对象的内存空间所占的资源

面向对象(二)

注意:1、调用析构函数的时机:在主函数return之后,最后一个右花括号之前。

           2、析构函数没有参数,因为要清理对象所占的资源,所以无法传参。

           3、销毁对象:(1)调用析构函数清理对象所占的资源

                                   (2)清理内存空间

           4、如果在程序中手动调用析构函数,系统还会调用,会发生两次调用同一资源,可能导致系统崩溃,所以不建议手动调用析构函数。

                手动调用析构函数和系统调用析构函数的区别:前者清理对象所占的资源,对象依然存在。后者连着对象一块清理。 

           5、先构造的对象后析构  

三、拷贝构造函数

时机:用一个已经存在的对象去初始化相同类型的新的对象时,调用拷贝构造函数

CGoods good1;

CGoods good2(“面包”,20,5.5);

CGoods good3=good2;//此时需要调用拷贝构造函数

现在有三个拷贝构造函数:

面向对象(二)  面向对象(二) 面向对象(二)

当需要调用拷贝构造函数时,分别调用三个拷贝构造函数,结果又会是怎样的呢?

调用第一个拷贝构造函数:第一个拷贝构造函数是浅拷贝,good2和good3指向同一块内存空间,构造的顺序是先good2、good3,所以析构的顺序是good3、good2,析构good3的时候,将申请的内存空间释放,析构good2的时候,指针就会指向一块空的区域,导致崩溃。

面向对象(二)

调用第二个拷贝构造函数:第二个拷贝构造函数中传入的参数是CGoods的一个实例rhs,因为是传值参数,所以会调用拷贝构造函数,因此。如果允许拷贝构造函数传值,就会在拷贝构造函数中调用拷贝构造函数,就会形成无休止的递归调用,导致栈溢出,因此,C++不允许拷贝构造函数传值参数。

调用第三个拷贝构造函数:结果成功,传的是引用,传入的直接是good2的地址,不会有无休止地调用拷贝构造函数所带来的栈溢出问题。

四、赋值运算符重载函数

时机:用已存在的对象给另一个已存在的对象赋值

例如:good3=good2;

1、系统给出的赋值运算符函数

面向对象(二)

如果调用系统提供的函数,则会有浅拷贝和内存泄漏问题:红色是没有赋值之前的内存分配,绿色是执行赋值操作后的内存分配,指针1和指针2指向同一块内存,析构时会崩溃,而且第二块内存区域也造成了内存泄漏问题,所以不采用系统提供的函数,用户需自己实现赋值运算符重载函数。

面向对象(二)

2、用户自己实现的函数

面向对象(二)

用户自己实现赋值运算符重载函数时需注意以下三点:

(1)防止自赋值

(2)释放旧资源

(3)开辟新资源,进行初始化




相关文章: