C++老鸟日记024 类的初始化与清除

微信公众号: 星点课堂

新浪微博:女儿叫老白

网易云课堂:女儿叫老白

网易云课堂免费课程:《C++跨平台开发中的编译错误》

网易云课堂免费课程:《C++老鸟日记》

----------------------------------------------------------------------------

6.1,6.2

引言:

----------------------------------------------------------------------------

       如果您用过C语言编程,那么您一定知道malloc()和free()。这两个接口用来申请和释放内存。C++中也支持这两个接口,但它提供了一种更好的手段来管理内存。我们今天就来讨论一下。

 

正文:

----------------------------------------------------------------------------

       在C++编码规范中,有一条非常重要的规则就是一定要为进行变量初始化。对于类对象来说,就是调用类的构造函数。如果我们没有提供类的构造函数,编译器会默认生成一个。当然,编译器不知道我们到底想要做哪些初始化,因此编译器生成的构造函数也许并不能满足我们的需求。所以,还是为类编写构造函数吧。

      

       // user.h

       class CUser {

public:

       CUser(int id, const string& name);

 

private:

       int m_nId;             // id号

       string m_strName;// 姓名

       string m_strAddress;// 住址

       bool m_bMarried; // 是否已婚

};

 

// user.cpp

#include “user.h”

// 构造函数写法1

CUser:: CUser (int id, const string& name):m_nId(id), m_strName(name),m_strAddress(“”),m_bMarried(false) {

}

      

       从在上述代码可以看出,类的构造函数与类同名,没有返回值。类的构造函数负责对成员变量进行初始化,并做一些其他必要的工作。上述示例代码中,成员变量的初始化直接写在构造函数的函数名的那一行。这是非常常用的方法。当然,您也可以写成这样:

// 构造函数写法2

CUser:: CUser (int id, const string& name) {

       m_nId = id;

       m_strName = name;

}

      

       请注意:如果按照前一个写法,类的成员变量初始化的顺序必须与头文件中定义的顺序保持一致,否则在gcc编译(或者其他编译器)可能会报错(跟编译器版本有关)。

       在实际开发过程中,我们可能有不同的构造需求,比如我们可以提供另外一个构造函数2:

       // user.h

       class CUser {

public:

       CUser(int id, const string& name);      // 构造函数1

       CUser(int id, const string& name, const string& addr, bool bMarried); //构造函数2

 

private:

       int m_nId;             // id号

       string m_strName;// 姓名

       string m_strAddress;// 住址

       bool m_bMarried; // 是否已婚

};

 

// user.cpp

#include “user.h”

// 构造函数1

CUser:: CUser (int id, const string& name):m_nId(id), m_strName(name),m_strAddress(“”),m_bMarried(false) {

}

// 构造函数2

CUser:: CUser (int id, const string& name,const string& addr, bool bMarried):m_nId(id), m_strName(name),m_strAddress(addr),m_bMarried(bMarried) {

}

 

如果我们定义了派生类,派生类的构造函数也需要调用父类的构造函数。

// student.h

#include user.h

class CStudent : public CUser {

public:

       CStudent(const string& school, const string& pro);

private:

       string m_strSchool;       // 学校

       string m_strPro;           // 专业

};

 

// student.cpp

#include “student.h”

// 构造函数

CStudent:: CStudent (const string& school, const string& pro):CUser (0, “”):m_strSchool(school), m_strPro(pro) {

}

从上述代码可以看出,子类的构造函数中,可以调用父类的构造函数(当然,也可以不调用,这完全取决于您的需要,不过一般情况下都是需要调用的)。然后才是子类成员的初始化。

       从这里我们也可以得出结论,在C++中,变量的初始化是按照从父类到子类的顺序。否则父类还没有初始化完毕的情况下,如果子类的构造函数调用了父类的某个接口,就很有可能出问题。

       避免在类的构造函数中抛异常,因为类还没有初始化完毕,完全处于一种未知状态。此时抛出异常,可能程序仍然无法继续正确运行。

      

       下面,我们再看一下类的析构。每个类都有一个析构函数,显然,在析构函数中,我们要做一些释放内存、断开联系之类的工作,总之是扫尾工作。当超出对象的作用域时,编译器会自动调用类的析构函数。

       // user.h

       class CUser

{

public:

       virtual ~CUser(){}

};

       请注意,在上述代码中,我们在析构函数前使用了virtual关键字。它是做什么用的呢?稍后我们会为大家解释。现在请继续看下文。

       // student.h

       #include “user.h”

       class CStudent : public CUser {

       public:

              ~CStudent(){}

}

 

// main.cpp

CUser* pUser = new CStudent(“qinghua”, “actor”);

……

if (NULL != ) {

delete pUser;

pUser = NULL;

}

现在我们来解答刚才的疑问。在上述代码中,我们定义了一个CUser的指针指向new出来的CStudent对象。这没有问题。在最后的代码中,我们把这个指针删除。请注意,是以CUser的身份删除该指针,因此调用的是CUser的析构函数。如果我们不把~CUser()前面加上virtual关键字,那么编译器的工作到此结束,它只负责析构CUser,不会调用~CStudent(),因此就可能导致CStudent中申请的内存泄漏或者~CStudent()中该做的工作没做。为父类CUser的析构函数加上了virtual关键字,就能保证编译器可以继续调用子类的析构函数。因此,程序可以把该做的工作做完。

 

结语:

----------------------------------------------------------------------------

       构造函数和析构函数负责类的初始化与清除工作能够正常进行,因此我们一定要注意按照规范编写构造函数与析构函数。

       1. 一定要编写构造函数、析构函数。

       2. 子类的构造函数中,先调用父类的构造函数,再对子类的成员变量初始化。

       3. 父类的析构函数前要使用virtual关键字。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

女儿叫老白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值