|
[VC++学习]《精通MFC》——第四章(II) 读书笔记
|
New操作符在堆中创建对象并返回执行该对象的指针。
Void* PASCAL operator new( size_t nSize);
Void* PASCAL operator new(size_t nSize, void* p);
Void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
第一种形式的实现细节:
Void* PASCAL CObject::operator new(size_t nSize)
{
#ifdef _AFX_DEBUG_CRT
//非调试版本
Return::operator new(nSize);
#else
//调试
Return ::operator new(nSize, _AFX_CLIENT_BLOCK, NULL, 0);
#endif //_AFX_NO_DEBUG_CRT
}
CObject的new操作符利用全局的new操作符分配内存。全局的new操作符有两种形式,一种形式仅分配对象所占的内存:
pResult = malloc(nSize);
而另一种形式的new操作符则还要分配额外的内存,保存内存分配信息以支持内存诊断:
pResult = _malloc_dbg(nSize, _NORMAL_BLOCK, NULL, 0);
如果在实现文件中包含了下面的宏:
#define new DEBUG_NEW
那么CObject第三种形式的new操作符将被调用。这时文件名和new操作符所在的行号被写到额外分配的内存块中。
每一个重载版本的new操作符都对应着一个delete的重载版本。
void PASCAL operator delete(void* p);
void PASCAL operator delete(void* p, void* pPlace);
void PASCAL operator delete(void* p, LPCSTR lpszFileName, int nLine);
delete运算符释放的new操作符分配的内存,以及为保存内存诊断信息额外分配的内存。
CObject提供的new和delete运算符能很好的发现内存泄露。
如果输出的诊断信息中无文件和行号信息,请检查是否在.cpp文件中包含了下面的宏定义:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
4.3 诊断功能
CObject的Dump成员和AssertValid成员提供了诊断功能。Dump成员类的内容提供调试输出,而AssertValid函数提供自定义测试以验证类对象的数据成员的一致性。
Dump成员
Dump成员定义如下:
Virtual void Dump(CdumpContext& dc)const;
dc表示转储上下文。转储上下文类似于I/O流。可以使用插入运算符(<<)向CDumpContext发送数据。
Dump成员只有在调试时才有意义,因此,要把Dump函数的声明和实现用#ifdef _DEBUG / #endif块括起来。
class CPerson:public CObject
{
public:
#ifdef _DEBUG
virtual void Dump(CDumpContext& dc)const;
#endif
CString m_firstName;
CStirng m_lastName;
//其它
};
如果定义了IMPLEMENT_DYNAMIC或IMPLEMENT_SERIAL宏,CObject的Dump将输出当前对象的类名:
#ifdef _DEBUG
void CObject:Dump(CDumpContext& dc)const
{
dc << "a" << GetRuntimeClass()->m_lpszClassName <<
"at" << (void*)this << "\n";
}
#endif //_DEBUG
重写Dump函数时,应先调用Dump的基类版本以转储基类对象的内容。然后为派生类的每个成员变量输出文本化说明和值。
AssertValid
CObject::AssertValid成员函数提供对对象内部状态的运行时检查。该成员只在 调试时有用,并且是const类型的成员.
CObjectd 的AssertValid仅断言当前对象不为NULL;
void CObject::AssertValid()const
{
ASSERT(this != NULL);
}
AssertValid应在对象的所有成员变量上执行断言,以验证它们包含有效值。
下面的实例显示如何声明AssertValid函数:
class CPerson:public CObject
{
protected:
CString m_strName;
float m_salary;
public:
#ifdef _DEBUG
virtual void AssertValid()const;
#endif
//...
};
当重写AssertValid时,在执行自己的检查之前请调用AssertValid的基类版本。然后使用ASSERT宏定义检查派生类特有的成员:
#ifdef _DEBUG
void CPerson::AssertValid()const
{
//先调用基类的成员
CObject::AssertValid();
//特殊检查
ASSERt(!m_strName.IsEmpty());
ASSERT(m_salary > 0);
}
#endif |
|
|
|