声明对象指针,调用构造、析构函数的多种情况
以下分析一下,声明对象指针,调用构造、析构函数的多种情况,先定义以下的一个基类与派生类。
class CBase
{
public:
CBase()
{
cout << "CBase()" << endl;
}
~CBase()
{
cout << "~CBase()" << endl;
}
};
class CDerived : public CBase
{
public:
CDerived()
{
cout << "CDerived()" << endl;
}
~CDerived()
{
cout << "~CDerived()" << endl;
}
};
1、只是声明一个对象指针,没有定义,所以不会分配内存,也不会调用构造函数。如下所示:
CBase *CBase1 = NULL;
/*
输出结果:
(NULL)
*/
2、声明一个基类指针,分配一个派生类对象空间,构造与直接声明派生类一样,析构的话只调用基类的析构函数,而不会调用派生类的析构函数。因为基类的析构函数未声明为虚函数。如下所示:
CBase *pCBase = new CDerived();
delete pCBase;
/*
输出结果:
CBase()
CDerived()
~CBase()
*/
3、在将CBase类的析构函数声明为虚函数时,再执行上述代码如下所示:
CBase *pCBase = new CDerived();
delete pCBase;
/*
输出结果:
CBase()
CDerived()
~CDerived()
~CBase()
*/
所以基类的析构函数必须定义为虚函数,否则子类对象析构时,将无法调用子类的析构函数,造成内存泄露。
4、而声明一个派生类指针,分配一个基类对象空间,会报错,因为基类指针可以指向派生类对象而派生类指针不可以指向基类对象。如下所示:
CDerived *pCDerived = new CBase(); //error
delete pCDerived;
再看下面这个例子:
class CTest
{
public:
CTest():name("misaka") { } // 初始化列表
void sayHello() const
{
cout << "hello" << endl;
}
void showName() const
{
cout << name << endl;
}
private:
string name;
};
1、因为只声明一个对象指针,而没有分配内存空间,所以没有给数据成员 name 分配内存,也不会调用构造函数,所以在试图打印 name 时会崩溃。
CTest *PCTest = NULL;
PCTest->sayHello(); //打印出"hello"
PCTest->showName(); //error,造成程序崩溃
2、声明一个对象指针并分配内存空间,就能调用构造函数,不再会崩溃。
CTest *PCTest = new CTest();
PCTest->sayHello(); //打印出"hello"
PCTest->showName(); //OK,打印出"misaka"
3、当然把 name 声明为静态变量也不会崩溃,因为在编译前系统已经给静态成员数据 name 分配了内存,如下所示:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
string CTest::name = "wangwu"; // 类外要初始化静态变量
class CTest
{
public:
CTest(){ }
void sayHello() const
{
cout << "hello" << endl;
}
void showName() const
{
cout << name << endl;
}
private:
static string name;
};
int main()
{
CTest *PCTest = NULL;
PCTest->sayHello(); //打印出"hello"
PCTest->showName(); //OK,打印出"wangwu"
return 0;
}
/*
输出结果:
hello
wangwu
*/