构造函数和析构函数

构造函数:

在创建一个对象时,我们通常要对其进行初始化,即就是为该对象的成员变量赋初值,因为一旦我们创建一对象,系统会为该对象分配一定大小的空间,若我们不对它进行初始化,该空间中的内容都是一些随机值,而对象是一个实体,它表现了事物的具体属性,应该有一个确定的值。C++中提供了构造函数来进行对象初始化的工作。

1.定义
构造函数是类中一种特殊的成员函数,它的名字与类名相同,无返回值,在创建该类对象时,由编译器自动调用构造函数,在对象的生命周期内只会被调用一次,其目的是初始化新对象,保证对象的每个数据成员都有一个合适的初始值。

2.构造函数的特性

  • 函数名与类名相同
  • 不具有任何类型,不返回任何值
  • 创建新对象时,编译器自动调用,在对象生命周期内仅调用一次
  • 构造函数可重载,调用哪个由实参决定
  • 无参构造函数和全缺省构造函数都被认为是缺省构造函数,而且一个类中缺省构造函数只能存在一个(避免二义性)
  • 可采用初始化列表的形式对成员变量进行初始化
  • 若用户未显示定义构造函数,系统会合成一个默认的构造函数(并非在任何时候都会合成,四种情况下会合成,后面会详述)
  • 不能被const修饰(因为构造函数的作用就是为对象中的各个成员进行赋值的,而用const修饰后,其对象中的内容就不能被更改,显然有悖常理,因此const对构造函数和析构函数都是非法的)

3.对象初始化

//日期类
class Data
{
public:
    Data(int year=0,int month=0,int day=0)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};

一般情况下,构造函数的参数我们通常给出缺省值,它提供了创建对象时的多种选择,它相当于好几个重载的构造函数,在对象创建中,给出实参或未给出实参都可调用该构造函数进行初始化,如:

int main()
{
    Data d1;
    Data d2(2018);
    Data d3(2018,4,27);
}

除了上面这种在函数体内对数据成员进行初始化外,我们还可以在函数首部实现,即采用初始化列表的方式。大多C++程序员喜欢用这种方式初始化成员变量

初始化列表:在函数首部末尾加一个冒号,接着是以逗号分隔的数据成员列表,每个成员变量后面跟一个括号,括号中是对其进行初始化的初始值或表达式。

这样:

Data(int year=0,int month=0,int day=0)
    :_year(year)
    ,_month(month)
    ,_day(day)
    {}

再来看这样一段代码:

class Data
{
public:
    Data(int year=0,int month=0,int day=0)
        :_year(year)
        ,_day(day)
        ,_month(_day)

    {}
private:
    int _year;
    int _month;
    int _day;
};

这里写图片描述

通过监视窗口我们发现,成员变量_month并未被初始化,还是原来的随机值。由此可以得出结论:

  • 初始化列表的功能只是初始化成员变量,并不代表这些变量的初始化顺序,初始化顺序由定义这些成员变量的顺序决定
  • 为了减少不必要的麻烦,最好不要用成员初始化成员,成员初始化的顺序尽量和定义的顺序保持一致

类中有一些成员,它们必须放在初始化列表的位置进行初始化:

  • 引用成员变量(引用在定义时必须初始化,指定其为哪个变量的别名)
  • const 成员变量(定义时也要初始化,因为后期不能修改)
  • 类类型成员(该类有非缺省的构造函数)

explicit关键字
C++中,对于单参的构造函数,编译器会默认将其参数转换成类类型对象(这里的单参是指一个参数或是除第一个参数外其他参数都有默认值)。

有些情况下,编译器这样的操作却违背了我们的本意,这时,我们在构造函数前加上explicit关键字,其作用是抑制由构造函数定义的隐式转换。

看例子:

class Test1
{
public:
    Test(int n)
    {
        _data=n;
    }
private:
    int _data;
};

class Test2
{
public:
    explicit Test(int n)
    {
        _data=n;
    }
private:
    int _data;
};

int main()
{
    Test1 t1=10;//隐式调用其构造函数,成功
    Test2 t2=20;//失败,不能隐式调用
    Test2 t2(20);//显示调用成功
    return 0;
}

因此:
普通构造函数能够被隐式调用,而explicit构造函数只能显式调用。
explicit只需要在类内构造函数声明前加上,在类外定义时不再重复


析构函数:

定义:在对象被销毁时,编译器自动调用析构函数做一些清理工作,与构造函数功能相反。

特性

  • 析构函数的函数名是在类名前加上~
  • 析构函数无参无返回值,不能重载,析构函数唯一
  • 一个类中有且只有一个析构函数,若未显式定义,系统自动生成缺省的析构函数
  • 对象生命周期结束,C++编译系统自动调用
  • 析构函数体内并不是删除对象,而是做一些清理工作

析构函数首先执行函数体,然后销毁成员,成员按初始化顺序的逆序销毁。
内置类型无析构函数,因此销毁内置类型什么也不做。
所以隐式销毁一个内置类型的成员,不会delete它所指的对象。
智能指针是类类型,具有析构函数,智能指针成员在析构阶段会被自动清除。

析构函数的调用时机???
只要对象被销毁,就会调用其析构函数

  • 从对象定义的作用域出来
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值