CObject
说到MFC学习就不得不说CObject 类,因为它是MFC大多数类的基类。所以有必要从“头”学起。
构造函数
CObject | 默认 构造函数. |
CObject | 拷贝 构造. |
operator delete | 特殊 delete 操作. |
operator new | 特殊 new 操作. |
诊断函数
AssertValid | 检测 this object's 完整性. |
Dump | 泄露诊断函数. |
串行化
IsSerializable | 检测是否支持串行化. |
Serialize | 加载或保存对象从/到档案. |
类型识别
GetRuntimeClass | Returns the CRuntimeClass structure corresponding to this object's class. |
IsKindOf | Tests this object's relationship to a given class. |
接下来,我们分别从MFC源代码及测试源代码及测试结果的角度分析。
CObject();
protected CObject(void); // 类声明
_AFX_INLINE CObject::CObject() // 仅是一个空的实现
{ }
CObject类是一个抽象类,不能直接new 对象。
例如:
CObject obj; // 这样写是无法编译的
默认构造函数是protected的,所以无法直接产生对象。仅能在其子类中产生。
CObject( const CObject& objectSrc );
private CObject(class CObject const &);
private operator=(class CObject const &);
这两个函数没有实现,只是声明为私有的。这样如果在了类中没有重载就不能进行拷贝操作。
CObject::CObject CObject( ); CObject( const CObject& objectSrc ); 参数: objectSrc 另一个CObject对象的参考。 说明:上述函数为标准的CObject构造函数。通过派生类的构造函数自动调用该函数的缺省形式。如果你的类可串行化(它引入了IMPLEMENT_SERIAL宏),那么在类的派生中必须使用缺省的构造函数(即没有参数的构造函数)。若不需要缺省的构造函数,请事先声明私有的和受保护的“空”构造函数。标准C 缺省类拷贝构造函数进行的是成员对成员的拷贝。如果需要你自己类的拷贝构造函数但现在没有,那么私有的CObject拷贝构造函数的存在将保证编译器发出错误消息。因此,若你的类需要这种能力,就必须提供拷贝构造函数。
CObject::CObject CObject( ); CObject( const CObject& objectSrc ); 参数: objectSrc 另一个CObject对象的参考。 说明:上述函数为标准的CObject构造函数。通过派生类的构造函数自动调用该函数的缺省形式。如果你的类可串行化(它引入了IMPLEMENT_SERIAL宏),那么在类的派生中必须使用缺省的构造函数(即没有参数的构造函数)。若不需要缺省的构造函数,请事先声明私有的和受保护的“空”构造函数。如果需要更多信息,请参阅联机文档“Visual C 程序员指南”中的“CObject类主题”。标准C 缺省类拷贝构造函数进行的是成员对成员的拷贝。如果需要你自己类的拷贝构造函数但现在没有,那么私有的CObject拷贝构造函数的存在将保证编译器发出错误消息。因此,若你的类需要这种能力,就必须提供拷贝构造函数。
Object.h
class AFX_NOVTABLE CObject
{
public:
// Object model (types, destruction, allocation)
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject() = 0; // virtual destructors are necessary
// Diagnostic allocations
void* PASCAL operator new(size_t nSize);
void* PASCAL operator new(size_t, void* p);
void PASCAL operator delete(void* p);
#if _MSC_VER >= 1200
void PASCAL operator delete(void* p, void* pPlace);
#endif
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// for file name/line number tracking using DEBUG_NEW
void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
#if _MSC_VER >= 1200
void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine);
#endif
#endif
// Disable the copy constructor and assignment by default so you will get
// compiler errors instead of unexpected behaviour if you pass objects
// by value or assign objects.
protected:
CObject();
private:
CObject(const CObject& objectSrc); // no implementation
void operator=(const CObject& objectSrc); // no implementation
// Attributes
public:
BOOL IsSerializable() const;
BOOL IsKindOf(const CRuntimeClass* pClass) const;
// Overridables
virtual void Serialize(CArchive& ar);
#if defined(_DEBUG) || defined(_AFXDLL)
// Diagnostic Support
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Implementation
public:
static const CRuntimeClass classCObject;
#ifdef _AFXDLL
static CRuntimeClass* PASCAL _GetBaseClass();
static CRuntimeClass* PASCAL GetThisClass();
#endif
};
Object.cpp
// special runtime-class structure for CObject (no base class)
const struct CRuntimeClass CObject::classCObject =
{ "CObject", sizeof(CObject), 0xffff, NULL, NULL, NULL };
CRuntimeClass* CObject::GetRuntimeClass() const
{
return _RUNTIME_CLASS(CObject);
}
#ifdef _AFXDLL
CRuntimeClass* PASCAL CObject::_GetBaseClass()
{
return NULL;
}
CRuntimeClass* PASCAL CObject::GetThisClass()
{
return _RUNTIME_CLASS(CObject);
}
#endif
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
ENSURE(this != NULL);
// it better be in valid memory, at least for CObject size
ASSERT(AfxIsValidAddress(this, sizeof(CObject)));
// simple SI case
CRuntimeClass* pClassThis = GetRuntimeClass();
ENSURE(pClassThis);
return pClassThis->IsDerivedFrom(pClass);
}
CObject* AFX_CDECL AfxDynamicDownCast(CRuntimeClass* pClass, CObject* pObject)
{
if (pObject != NULL && pObject->IsKindOf(pClass))
return pObject;
else
return NULL;
}
#ifdef _DEBUG
CObject* AFX_CDECL AfxStaticDownCast(CRuntimeClass* pClass, CObject* pObject)
{
ASSERT(pObject == NULL || pObject->IsKindOf(pClass));
return pObject;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// Diagnostic Support
#ifdef _DEBUG
void AFXAPI AfxAssertValidObject(const CObject* pOb,
LPCSTR lpszFileName, int nLine)
{
if (pOb == NULL)
{
TRACE(traceAppMsg, 0, "ASSERT_VALID fails with NULL pointer.\n");
if (AfxAssertFailedLine(lpszFileName, nLine))
AfxDebugBreak();
return; // quick escape
}
if (!AfxIsValidAddress(pOb, sizeof(CObject)))
{
TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal pointer.\n");
if (AfxAssertFailedLine(lpszFileName, nLine))
AfxDebugBreak();
return; // quick escape
}
// check to make sure the VTable pointer is valid
ASSERT(sizeof(CObject) == sizeof(void*));
if (!AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE))
{
TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal vtable pointer.\n");
if (AfxAssertFailedLine(lpszFileName, nLine))
AfxDebugBreak();
return; // quick escape
}
if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize, FALSE))
{
TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal pointer.\n");
if (AfxAssertFailedLine(lpszFileName, nLine))
AfxDebugBreak();
return; // quick escape
}
pOb->AssertValid();
}
void CObject::AssertValid() const
{
ASSERT(this != NULL);
}
void CObject::Dump(CDumpContext& dc) const
{
dc << "a " << GetRuntimeClass()->m_lpszClassName <<
" at " << (void*)this << "\n";
UNUSED(dc); // unused in release build
}
#endif //_DEBUG
////////////////////////////////////////////////////////////////////////////
// Allocation/Creation
CObject* CRuntimeClass::CreateObject()
{
ENSURE(this);
if (m_pfnCreateObject == NULL)
{
TRACE(traceAppMsg, 0,
_T("Error: Trying to create object which is not ")
_T("DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n"),
m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
TRY
{
pObject = (*m_pfnCreateObject)();
}
END_TRY
return pObject;
}
////////////////////////////////////////////////////////////////////////////
// Class loader & class serialization
BOOL CObject::IsSerializable() const
{
return (GetRuntimeClass()->m_wSchema != 0xffff);
}
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
pModuleState->m_classList.AddHead(pNewClass);
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
}