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

C++ 之 构造函数与析构函数

2016-03-31 11:47 429 查看
一、构造函数

1. 构造函数的理解

构造函数用于类的对象初始化,是基于具体对象而言的。我们需要在构造对象时跟据传入的参数进行函数重载,分为默认构造函数(可以显示声明,也可以引式声明)、自定义类型(根据传入的参数类型,参数个数,选择最优匹配的)。基于对象的初始化目的,构造函数时不需要任何返回值的(加入返回值反而是画蛇添足了)。

值得一提的是,构造函数和成员函数(包括静态和非静态)都是属于类的,其存储地址是与具体对象分开存储的。也就是说,一个类只存在一个样本,不属于实例化对象的空间。在采用sizeof(类)时,不需要考虑进去。

构造函数三法则:

(1)如果没有定义复制构造函数,编译器会自动生成默认赋值构造函数。

(2)如果定义了其他构造函数(包括复制构造函数),编译器绝不会生成默认构造函数(此时要显示的定义不带参数的构造函数,为了能定义Base base;这样的实例)。

2. 复制构造函数和对象赋值、运算符operator = 重载

要明白这几个概念,先得清楚几个概念。

(1)在定义一个空类,经过C++处理后,编译器都做了些什么。当用户没有声明时,编译器就会为其声明(编译器版本)一个默认的构造函数、一个copy构造函数、一个copy assignment操作符和一个析构函数。所有这些函数的都是pubic并且inline类型的。

(2)在C++中规定,初始化和赋值是不同的,对象的成员变量的初始化动作发生在进入构造函数本体(也就是{}中的内容)之前。

当类中同时存在复制构造函数和运算符重载最本质的区别是,在进行操作时是否已经为对象分配了空间。

class Base {...}
Base base1;                             .....(1)
Base base2 = base1;                     .....(2)
Base base3(base1);                      .....(3)
Base base4;                             .....(4)
base4 = base1;                          .....(5)
base4(base1);                           .....(6)


上述形式中(1)(4)调用的是默认构造函数,(2)(3)是复制构造函数,(5)调用的运算符重载。(6)比较特殊,没有operator运算符,都分配了空间,调用的是复制构造函数。

值得一提的是(2)(3)之间是有效率的区别的。在(2)中复制构造函数base2先调用的是默认的构造函数bese2(),再调用赋值操作,相当于浪费了默认的构造函数操作。在(3)中会采用成员初始化列表形式,直接将base1中的成员变量赋值,效率较高。


Q:若用户没有定义copy构造函数,则编译器自动生成一个缺省的copy构造函数,它可能会产生什么问题?

A:当对象含有指针数据成员,并用它初始化同类型的另一个对象时,缺省的拷贝构造函数只能将该对象的数据成员复制给另一个对象,而不能将该对象中指针所指向的内存单元也复制过去。这样,就可能出现同一内存单元释放两次,导致程序运行出错。

二、析构函数

与构造函数相对应,没有返回类型,并且没有任何参数类型,只有只有一个(因为一个实例只会调用一个构造函数,所以就算声明了多态构造函数,也只有一个析构函数)。在类中没有声明析构函数,编译器会为类声明默认的析构函数,在生命周期结束时,用于释放类的对象在其生命周期间所申请的资源。

C++编程最难的一部分之一,便是了解何时需要定义析构函数而何时不需要。

1.虚析构函数的使用

C++中,当derived class对象精油一个base class指针被删除,而该base class带着一个非虚虚构函数,其结果未定义–实际执行时通常时对象的derived成分没有被销毁。这就导致了内存泄露,派生类的对象没有被释放,造成了“局部销毁”

两个法则:

(1)带多态性质的基类应该声明一个virtual析构函数。如果类带有任何virtual函数,它就应该拥有一个虚析构函数。

(2)classes的设计目的如果不是作为base class使用,或不是为了具备多态性,它就不应该声明为virtual析构函数。(会导致额外的运行时开销等)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: