중복되는 정보인지는 일단 찻아보기는 했지만 못봤습니다. 하지만 중복정보라면 코멘트부탁해요. 삭제하겟습니다.
Builder에는 많은 유용한 컨테이너들이 많습니다.
문제는 이것들이 전부 TObject형만 담을 수 있는지라 힙에서만 생성이 됩니다. TObject를 바로 상속받은 Class로 설계하면 new로만 생성시킬수 있으므로 자동변수나, 지역변수처럼 마음대로 사용하지 못하죠.
힙에 생성하면 auto ptr등을 쓰는등 메모리 관리에 신경써야 하고 좀 귀찮은 코드가 많아집니다.
개인적으로는 클래스를 설계할 때는 플랫폼에 영향을 가급적 받지 않게 하려고 신경쓰는 편이라 플랫폼에 영향이 없는 C++고유의 별도 최상위 클래스를 설계하고 이넘을 상속받아 컨테이너에 담거나 때로는 지역변수로, 때로는 전역변수로, 때로는 자동변수로 마구잡이로 끌고 다니며 쓰고 있습니다.
빌더에서는 빌더 VCL의 훌륭한 컨테이너들도 많구요. 또한 Grid도 훌륭한 컨테이너입니다.
예를 들면 Grid의 각 Row나 Cell마다 자신의 값을 담고 있는 Object를 참조하게 넣어두면 나중에 수정이나 참조시 일일이 별도의 참조리스트를 따라다니며 찻아 다닐 필요가 없이 바로 자신의 값을 가르키는 Object를 참조할 수 있습니다.
예를 들면 그리드의 한 Row가 고객의 한개 Rocord를 가르키고 있다면 DB에서 읽어들인 고객정보를 담은 class의 참조 포인터를 Grid의 해당 Row Object에다가 담아두면 Grid에서 뭔가 변화가(값이 변하던가, 위치가 변하던가)있더라도 결과를 반영할때 해당하는 Row의 값에해당하는 것을 별도의 리스트를 찻아 다닐 필요가 없이 바로 해당하는 Row의 Object를 꺼내서 반영하면 됩니다.
(개인적인 이유로 들어오는 소스가 각가 다릅니다. 때로는 DB, 때로는 XML, 때로는 File, 해서 DB EDIT컴포넌트는 별로 사용하지 않습니다.)
문제는 VCL컨테이너들은 TObject 형밖에 담을 수 없는데 여기에 바로 사용자가 정의한 class를 담을 수 없으므로 사용자가 정의한 클래스에 TObject를 포함시켜서 사용자 정의형 클래스도 마음대로 VCL컴포넌트에 담을 수 있게 해 줄 수 있습니다.
아래는 그 소스구요.
원리는 간단합니다. 사용자 정의형 클래스 CMyObject 에 TObject형 class를 상속받은 CMyVCLObject 클래스를 맴버로 포함시키고 TObject 형 클래스가 필요하면 이 CMyVCLObject를 넘겨주면 되죠. 그리고 사용자 정의형 CMyCMyObject 의 생성자에 CMyVCLObject를 생성하고 CMyObject 파괴자에 CMyVCLObject를 삭제 해주면 메모리 신경 쓰지 않아도 됩니다.
// Head 입니다.
class CMyVCLObject;
class CMyObject
{
private:
// 자식들이 삭제될시 처리할게 있으면 상속후 override.
virtual void clearObject(void) {}
public:
CMyObject(void);
virtual __fastcall ~CMyObject(void);
public:
// 이 Method는 자식들이 혼자 지워보겟다고 virtual로 선언하지말것. 자식들은 필요시 위의 clearObject Method를 override해서 처리요망.
// Template method pattern
void Clear(void)
{
this->clearObject();
}
void setVCLObject(CMyVCLObject *pVCLObject) {this->m_pVCLObject = pVCLObject;}
CMyVCLObject *getVCLObject(void) {return this->m_pVCLObject;}
private:
CMyVCLObject *m_pVCLObject;
};
//---------------------------------------------------------------------------
// VCL 컨테이너에 담기위한 TObject 형.
class CMyVCLObject : public TObject
{
private: // 혼자 생성금지.
CMyVCLObject(void) {}
public:
CMyVCLObject(CMyObject *pMyObject);
virtual __fastcall ~CMyVCLObject(void);
CMyObject *getObject(void) {return this->m_pObject;}
private:
CMyObject *m_pObject;
};
//---------------------------------------------------------------------------
// ************* CPP 입니다.
CMyObject::CMyObject(void)
{
this->m_pVCLObject = new CMyVCLObject(this);
this->Clear();
}
//---------------------------------------------------------------------------
__fastcall CMyObject::~CMyObject(void)
{
delete this->m_pVCLObject;
}
//---------------------------------------------------------------------------
CMyVCLObject::CMyVCLObject(CMyObject *pMyObject)
{
this->m_pObject = pMyObject;
this->m_pObject->setVCLObject(this);
}
//---------------------------------------------------------------------------
__fastcall CMyVCLObject::~CMyVCLObject(void)
{
this->m_pObject->setVCLObject(NULL);
}
//---------------------------------------------------------------------------
// 사용예 입니다.
class CBank : public CMyObject
{
public:
CBank(void) {}
virtual __fastcall ~CBank(void) {}
void ClearCustomList(void)
{
m_customList.Clear();
}
private:
void clearObject(void)
{
this->ClearCustomList();
}
public:
int m_nDBIdx;
AnsiString m_szAccount;
int m_nVersion;
unsigned m_nDummy;
public:
CMyObjectList m_customList;
};
//---------------------------------------------------------------------------
CMyObject class 를 상속받은 CBank class 가 위와같이 있다면,
전역변수
CBank g_Bank; // 문제 없습니다.
지역변수
bool findBank(int nCustomIdx)
{
CBank bank; // 문제없습니다.
CBank *pBank = new CBank(); // 문제없습니다.
....
}
pBank 형 포인터에 데이터를 담고 있다면..
VCL 컨테이너에 담기.
this->CustomGrid->Cells[0][i] = pBank->m_szAccount; // 그리드에 값표시.
this->CustomGrid->Objects[0][i] = pBank->getVCLObject(); // 그리드의 해당 Row에 CBank 포인터 담아두기.
VCL 컨테이너에서 꺼내기.
CMyVCLObject *pObject = dynamic_cast<CMyVCLObject *>(CustomGrid->Objects[0][i]);
CBank *pBank = dynamic_cast<CBank *>(pObject->getObject());
TObject형 컨테이너에 담아두려는 class는 전부 CMyObject 를 상속받아야 합니다. TObject 형 컨테이너에 담을 수 있는 클래스 들도 전부 TObject를 상속받아 쓰죠.
또한 간단한것이므로 복사 생성자등에 신경쓰지 않았고 가져온 값등의 유효성은 체크하지 않았으므로 이 팁의 목적은 사용방법에 있습니다. 일부 코드는 실제로 복사해서 그대로 가져 쓸 순있지만 유효성이나 버그체크는 별도로 하셔야 합니다.
필요하신분 유용하시기 바랍니다.
VCL 을 다뤄보면 누구나 한번 쯤은 부딪히는 내용이고 누구나 한번쯤은 어떤 식으로 해결할까 고민하는 내용이죠.
좋은 해결 방법 같습니다.
그런데 참고적으로 말씀드리면, VCL에 있는 TObject * 데이타를 담을 수 있게 한 것은 편의적인 측면에서
TObject* 형을 쉽게 포인트로 담게 한 것일뿐, 어떤 형태의 포인트나 4바이트 데이타가 들어가던지 상관이 없습니다.
즉 어떤 VCL 인스턴스에 대한 포인트를 담아도 되지만,
어떤 셀에 대한 ID 성격의 int 정수 값을 담아도 상관은 없는 것입니다.
VCL 컴포넌트의 TObject 컨테이너는 범용이 목적이므로,
TObject 후손을 동적 생성해서 그 포인트를 반드시 담아야 할 이유는 없습니다.
실제 사용에 있어서도 TObject 형이라기 보다는 어떤 4바이트 포인트가 정수 값으로 다뤄지는 경우도 많습니다.
예시를 보이신 것에 기준하자면
데이타 struct 구조체 또는 클래스를 메모리에 만들고 그것에 대한 포인트를 가르키게 하는 방법이 많이 쓰입니다.
this-> 는 생략할 수 있는데 일일이 쓰시는 것을 보니 독특한 코딩 습관을 가지신 것 같습니다.