http://rapidshare.com/files/349564969/ChZoneEXE.zip.html[
^]
http://rapidshare.com/files/349565255/ChZoneSLN.zip.html[
^]
Introduction
Hello.
It is sometime necessary to control the changes of an object to its initial state, to register and may be reset they rapidly. Here I would try to show a possible way for the scanning of an object with the simple members (their types support the
operator ==
). And... I would begin from the end and describe the possible usage firstly... :)
Using of Code
Step 1. Declare your object as changeable and mark the members to scan
...
#include "ChangeableObject.h"
...
class CChZoneDlg : public CDialog
{
DECLARE_CHANGEABLE_OBJECT()
protected:
Changeable<int> m_iChoice1;
Changeable<int> m_iChoice2;
Changeable<int> m_iChoice3;
Changeable<int> m_iChoice4;
Changeable<int> m_iState;
Changeable<CString> m_cszEntry;
public:
CChZoneDlg(CWnd* pParent = NULL); ...
Step 2. Implement your changeable object and insert its marked members in to the scanning engine
IMPLEMENT_CHANGEABLE_OBJECT(CChZoneDlg)
CChZoneDlg::CChZoneDlg(CWnd* pParent )
: CDialog(CChZoneDlg::IDD, pParent)
, m_iChoice1(0)
, m_iChoice2(1)
, m_iChoice3(2)
, m_iChoice4(3)
, m_cszEntry(_T("Hello world"))
, m_iState(1)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
ADD_CHAHNGEABLE_CHECK(m_iChoice1)
ADD_CHAHNGEABLE_CHECK(m_iChoice2)
ADD_CHAHNGEABLE_CHECK(m_iChoice3)
ADD_CHAHNGEABLE_CHECK(m_iChoice4)
ADD_CHAHNGEABLE_CHECK(m_cszEntry)
ADD_CHAHNGEABLE_CHECK(m_iState)
RefreshShadow();
}
Step 3. Using of changeable objects interface
That is all :) Now your object has the following levers:
-
void RefreshShadow()
- to remember the actual state of its members (see example above)
-
bool IsChanged()
- to determinate the fact of the changes:
void CChZoneDlg::OnOK()
{
UpdateData(TRUE);
int iAnswer(IDYES);
if (IsChanged()) {
iAnswer = MessageBox(_T("Do you want to save your changes ?"),
_T("Changes have been found..."),
MB_YESNOCANCEL | MB_ICONQUESTION);
if (IDYES == iAnswer) {
}
}
if (IDCANCEL != iAnswer) {
CDialog::OnOK();
}
}
-
void BackToShadow()
- to reset the changes and take the last marked (by
RefreshShadow()
) state:
void CChZoneDlg::OnReset()
{
BackToShadow();
UpdateData(FALSE);
}
Implementation
Woult you still like to ask how does it work ? :)
Sorry if it was not useful for you...
...and elsewise - well, we could observe the implementations code:
#pragma once
#include "afxcoll.h"
class CAbstractChangeable
{
public:
virtual void BackToShadow() = 0; virtual void RefreshShadow() = 0; virtual bool IsChanged() = 0; };
template <typename T, class Abstraction = CAbstractChangeable>
class Changeable : public Abstraction
{
T m_original, m_shadow;
public:
Changeable() {};
Changeable(const T& init) { m_original = m_shadow = init; };
operator T&() { return m_original; };
T* operator &() { return &m_original; };
virtual void BackToShadow() { m_original = m_shadow; };
virtual void RefreshShadow() { m_shadow = m_original; };
virtual bool IsChanged() { return m_shadow != m_original; };
Changeable* GetThis() { return this; };
};
class CChangeableArray : public CPtrArray
{
public:
CChangeableArray();
virtual ~CChangeableArray();
void MakeSame(bool bForwards); bool IsChanged(); };
#define DECLARE_CHANGEABLE_OBJECT() \
private: \
CChangeableArray m_cChangeableArray;\
void BackToShadow(); \
void RefreshShadow(); \
public: \
bool IsChanged();
#define IMPLEMENT_CHANGEABLE_OBJECT(Class) \
void Class##::BackToShadow() { m_cChangeableArray.MakeSame(false); } \
void Class##::RefreshShadow() { m_cChangeableArray.MakeSame(true); } \
bool Class##::IsChanged() { return m_cChangeableArray.IsChanged(); }
#define ADD_CHAHNGEABLE_CHECK(Member) \
m_cChangeableArray.Add(Member.GetThis());
#include "StdAfx.h"
#include "ChangeableObject.h"
CChangeableArray::CChangeableArray()
{
}
CChangeableArray::~CChangeableArray()
{
}
void CChangeableArray::MakeSame(bool bForwards)
{
int iCount(GetCount());
while (iCount--) {
CAbstractChangeable* pChangeable = (CAbstractChangeable*) GetAt(iCount);
if (pChangeable) {
if (bForwards) {
pChangeable->RefreshShadow(); } else {
pChangeable->BackToShadow(); }
}
}
}
bool CChangeableArray::IsChanged()
{
int iCount(GetCount());
while (iCount--) {
CAbstractChangeable* pChangeable = (CAbstractChangeable*) GetAt(iCount);
if (pChangeable &&
pChangeable->IsChanged()) {
return true; }
}
return false;
}
Limitations
Please don't use the technique with the pointer-members because only the pointer (and not their contents) will be compared (and may be reseted...) ! Another solution (pointers case) could be a object's memory dump by its
Serialize(..)
method - to (re)set the states and on-dump...
memcmp(..)
- to compare them... :)
Points of Interest
Is there a way to iterate the C++ class members addresses directly ?
Thank you ! :)