//---------------------------------------------------------------------------
// 김태성의 C++빌더 : VCL Style 클래스의 자동화를 위한 스마트 TTVCL, TTClass
//---------------------------------------------------------------------------
VCL Style 클래스는 반드시 힙에 생성해야 한다. 그래서 반드시
XClass *p = XClass(args);
식으로 생성해야 한다. 그리고 사용뒤에는 반드시
delete p;
로 소멸시켜야만 한다.
그냥 보통의 C++ 클래스처럼
XClass xclass;
식으로 생성이 되지 않는다.
이것이 C++ 프로그래머에겐 조금 불편한 사항 중에 하나이다.
얼마전에 필자는, 이러한 불편을 개선하고 프로그래밍에서의 객체처리 자동화를 지원하기 위해
new 가 아닌 클래스 선언으로만 생성할 수 있게 약간의 래핑을 한
KTStringList 와 KTList 를 소개한 바가 있다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=612
또한, 이전 강좌에서는 Tnew 클래스를 소개하여,
일반 변수나 클래스의 배열을 지역변수 쓰듯이 사용할 수 있게 했다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tutorial&no=103
즉 여러가지 경우에 있어 delete 로 짝을 맞춰 신경써서 지워줄 필요없이
자동으로 객체가 소멸하게 함으로써, 보다 안전하고 delete 신경쓰지 않는 편리한 프로그래밍을 가능하게 했다.
예외가 발생해 루틴의 중간에 함수를 빠져나갈 때를 대비하지 않은 경우라도
안전하게 소멸되기 때문에, 그 가치는 제법 있다고 하겠다.
오늘은 이를 일반적인 컴포넌트와 폼 그리고 VCL Style 클래스에 일반적으로 적용할 수 있는
템플릿 클래스를 제작해 소개한다.
먼저 컴포넌트와 폼 등을 정적으로 생성하여 사용할 수 있는 TTVCL을 소개한다.
모든 컴포넌트와 폼등은
TForm1 *form = new TForm1(Application);
TButton *btn = new TButton(form);
식으로 동적으로 생성되어야 한다.
이를 delete 가 없는 스마트 클래스화한 것이 바로 TTVCL 이다.
그러므로 정적으로 다음과 같이 생성 할수 있다.
TTVCL<TForm1> form(Application);
TTVCL<TButton> Btn1(form);
이 두 줄은 위의 두 줄과 같다.
하지만 객체를 메모리에서 지우기 위해 delete 할 필요없다.
자동으로 소멸하기 때문이다.
여기서 하나, 언어 표현에 약간의 정확지 않은 부분이 있다.
사실 정적이라는 표현은 new 로 동적으로 생성하는 것에 대한 대비표현일뿐
여기서는, 사실은 동적으로 생성하고 다루기만 정적인 인스턴스인양하는 것 뿐이다.
다음은 TTVCL 소스이다.
//---------------------------------------------------------------------------
// 일반적인 VCL 스타일 클래스를 정적으로 생성하는 템플릿 클래스
// 단, 생성자의 인자를 TComponent 로 하는 클래스이어야 함.
// 모든 컴포넌트와 폼 등의 수많은 VCL Style 클래스가 해당됨.
template<class T>
class TTVCL
{
public:
T *p;
public:
TTVCL(TComponent *Owner)
{
p = new T(Owner);
}
~TTVCL()
{
delete p;
}
T* operator->() { return p; }
T& operator*() { return *p; }
operator T*() { return p; }
};
//---------------------------------------------------------------------------
정말 간단하다.
그런데 VCL Style 클래스에는 TComponent를 생성 인자로 하는 것 뿐만 아니라
인자 자체가 없이 사용되는 것도 있다.
TStringList, TList 등과 같은 것들이다.
이의 정적인 생성을 지원하기 위한 템플릿클래스가 바로 아래의 TTClass 이다.
이미 필자는 KTStringList 와 KTList 를 소개하여
정적 객체로 사용할수 있게 했지만,
여기서는 그것을 일반화 했다. 즉 인자가 없는 모든 VCL 클래스에 다 사용할 수 있게 한 것이다.
물론 편의성은 KTStringList, KTList가 조금 더 있지만
여기서는 일반화된 템플릿 클래스이므로 다른 VCL 클래스에 적용해서 사용할 수 있다.
그래서
TTClass<TStringList> strongs;
TTClass<TList> lists;
식으로 사용 가능하다.
아래는 소스이다.
//---------------------------------------------------------------------------
// 일반적인 VCL 스타일 클래스를 정적으로 생성하는 템플릿 클래스
// 생성자의 인자를 가지지 않는 클래스만 사용할 수 있다.
// TStringList, TList 등...
template<class T>
class TTClass
{
public:
T *p;
public:
TTClass()
{
p = new T;
}
~TTClass()
{
delete p;
}
T* operator->() { return p; }
T& operator*() { return *p; }
operator T*() { return p; }
};
//---------------------------------------------------------------------------
이것 역시 정말 간단하다.
그런데 TTVCL 과 TTClass 구조가 거의 같다.
다른 점이라면 생성자 부분만 틀리다.
이 둘을 통합해서 처리할 방법이 없을까?
안타깝게도 C++의 템플릿의 구조 문제로 통합은 되지 않는다.
보통 템플릿 클래스는 실제 사용되어져야만 컴파일 되어 약간의 컴파일 시간을 더 소요하고,
컴파일된 코드는 지정한 클래스의 형별로 바이너리로 생성되므로,
실행화일 크기를 조금 더 증가 시킨다는 것은 상식이다.
그러나, C++빌더 컴파일러는 우수해서,
아주 복잡한 큰 템플릿 클래스가 아니라면 컴파일 시간은 크게 소요하지 않고,
위 같이 간단한 템플릿 클래스인 경우는 실행화일 크기에 미치는 영향도 아주 작다.
아래는 사용 예이다.
//---------------------------------------------------------------------------
// 같은 폼을 하나 더 만드는 예제
void __fastcall TForm1::Button3Click(TObject *Sender)
{
TTVCL<TForm1> form(Application);
form->Left = 0;
form->Top = 0;
TTVCL<TButton> Btn1(form);
Btn1->Parent = form;
Btn1->Top = 100;
Btn1->Left = 100;
Btn1->Width = 200;
Btn1->Height = 40;
Btn1->Caption = "동적 생성 버턴입니다.";
form->ShowModal();
// 정적으로 생성된 객체는 마지막에 생성된 것이 먼저 사라진다.
// 위에서 Btn1 이 먼저 소멸되고 다음 form 이 소멸된다.
}
//---------------------------------------------------------------------------
// 패널을 생성해 잠시 윈도를 가리는 예제
void __fastcall TForm1::Button4Click(TObject *Sender)
{
TTVCL<TPanel> a(this);
a->Parent = this;
a->Align = alClient;
a->Color = clWhite;
a->Caption = "패널로 잠시 가렸습니다.";
Update();
MessageBox(Handle, "확인.", "pause", MB_OK);
}
//---------------------------------------------------------------------------
// 메모에 TStrings 표시 예제.
void __fastcall TForm1::Button5Click(TObject *Sender)
{
TTClass<TStringList> s;
s->Add("테스트입니다");
s->Add("1");
s->Add("2");
s->Add("4");
s->Add("끝");
s->Insert(3, "3 번째");
Memo1->Lines = s;
}
//---------------------------------------------------------------------------
아주 약간의 프로그래밍의 편의성이 증가할 것이지,
생각보다 도움이 될지는 각자가 판단하기 바란다.
중요한 것은 이러한 자동화는 버그를 줄이고 편리한 프로그래밍 환경을 만드는데 도움이 된다는 사실이다.
[첨부파일]
첨부된 TTClass.h 는 두개의 템플릿 클래스인 TTVCL, TTClass 뿐만 아니라
이전에 소개한 Tnew 까지 한데 넣었다.
아무래도 연관성이 높아 한데 두는게 좋을것 같아서이다.
//---------------------------------------------------------------------------
// 김태성 cppbuilder@naver.com
// 이 강좌는 아무 곳에나 비상업적인 용도에 한해 내용 변경 없이 원래의 출처를 명시하여
// 배포할 수 있습니다. 단, 필자의 이메일로 게제 사실을 통보해야 합니다.
//---------------------------------------------------------------------------