在工作中Review Code的时候,发现有些开发人员,对C++的多态性认识的不是很全面,往往在使用过程中犯错。在这里,简单的描述一下,希望对一些朋友有帮助。
故事描述:传统的胶片单反相机简称为SLR,其主要部分是:反光板(Reflector)、快门(Shutter)、内置测光表(Exposure Meter)。现在流行的数码单反相机简称DSLR,其主要部件除了上诉三个主要部件外,还需要一个感光元器件CMOS(或者是CCD)。
下面代码是关于单反相机的一组类结构。
class Reflector
{
public:
Reflector()
{
printf("%s/n", "Create an reflector");
}
~Reflector()
{
printf("%s/n", "Destroy an reflector");
}
};
class Shutter
{
public:
Shutter()
{
printf("%s/n", "Create a Shutter");
}
~Shutter()
{
printf("%s/n", "Destroy a Shutter");
}
};
class ExposureMeter
{
public:
ExposureMeter()
{
printf("%s/n", "Create an Exposure Meter");
}
~ExposureMeter()
{
printf("%s/n", "Destroy an Exposure Meter");
}
};
class CMOS
{
public:
CMOS()
{
printf("%s/n", "Create a CMOS");
}
~CMOS()
{
printf("%s/n", "Destroy a CMOS");
}
};
class SLR
{
public:
SLR()
{
m_pShuter = new Shutter();
m_pRef = new Reflector();
m_pEMeter = new ExposureMeter();
}
~SLR()
{
delete m_pShuter;
delete m_pRef;
delete m_pEMeter;
}
protected:
Shutter *m_pShuter;
Reflector *m_pRef;
ExposureMeter *m_pEMeter;
};
class DSLR : public SLR
{
public:
DSLR()
{
m_pCMOS = new CMOS();
}
~DSLR()
{
delete m_pCMOS;
}
protected:
CMOS *m_pCMOS;
};
下面做一个很简单的例子
void main()
{
DSLR *pDslr = new DSLR();
printf("/n/n");
delete pDslr;
}
输出结果:
Create a Shutter
Create an reflector
Create an Exposure Meter
Create a CMOS
Destroy a CMOS
Destroy a Shutter
Destroy an reflector
Destroy an Exposure Meter
从这个简单的例子中我们可以看出,在实例化子类的时,首选需要调用基类的构造函数,然后才是子类的构造函数;销毁时,首先调用子类的析构函数,然后才是基类的析构函数。虽然,这是一个很简单的基础知识,但是却很重要。
我们修改一下main函数中的内容。
void main()
{
DSLR dslr;
printf("/n/n");
SLR *pSlr = NULL;
pSlr = &dslr;
int SizeSLR = sizeof(*pSlr);
int SizeDSLR = sizeof(dslr);
printf("%s%d/n", "SLR Size:", SizeSLR);
printf("%s%d/n", "DSLR Size:", SizeDSLR);
}
输出结果:
Create a Shutter
Create an reflector
Create an Exposure Meter
Create a CMOS
SLR Size:12
DSLR Size:16
从上述结果看,当pSlr = &dslr;该行执行结束后,pSlr指向的内存地址虽然没有变,但是包含的内容被截断,缺少了CMOS对象。这个现象,需要引起重视。
再次修改main函数内容。
void main()
{
SLR *pSlr = new DSLR();
printf("/n/n");
delete pSlr;
}
输出结果:
Create a Shutter
Create an reflector
Create an Exposure Meter
Create a CMOS
Destroy a Shutter
Destroy an reflector
Destroy an Exposure Meter
从输出结果,可以看出来CMOS指针没有被释放,产生了内存泄漏。这是什么原因呢?
根本原因,是由于基类SRL的析构函数不是虚函数,所以在销毁SLR类指针的时候直接调用SLR的析构函数,导致了内存泄露。
现在我们修改SLR析构函数为虚函数,然后重新执行这段代码。
输出结果:
Create a Shutter
Create an reflector
Create an Exposure Meter
Create a CMOS
Destroy a CMOS
Destroy a Shutter
Destroy an reflector
Destroy an Exposure Meter
这次完全释放了所占用的资源,达到了我们的目的。这个问题是经常发生的错误,也是很严重的问题,需要我们在实际开发中提高警惕。