C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[966] [퀴즈] Form 생성자 다형성의 문제점
장성호 [nasilso] 9005 읽음    2010-03-13 16:34
음..

Form의 생성자를 다형성해서 쓰는 경우가  있으시나요?
개인적으로 가끔 있는데..

class TForm2 : public TForm
{
__published:	// IDE-managed Components
   void __fastcall FormCreate(TObject *Sender);
private:	// User declarations
public:		// User declarations
   __fastcall TForm2(TComponent* Owner);
   __fastcall TForm2(TComponent* Owner,String sName)
         : TForm(Owner)
   {
      this->Caption=sName;
   }
};
//---------------------------------------------------------------------
//다음과 같이 사용할수가 있지요..
void __fastcall TForm1::Button4Click(TObject *Sender)
{
   TForm2 *frm=new TForm2(this,Edit1->Text);
   frm->ShowModal();
   delte frm
}
//-----------------------------------------------------------------------




[Form생성자 다형성이 안되는 경우]
그런데 다음과 같은 Form의 생성자는  좀 문제가 있습니다.
   __fastcall TForm2(TComponent* Owner,int iNumber)
         : TForm(Owner)
   {
      this->Tag=iNumber;
   }

//-----------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
   TForm2 *frm=new TForm2(this,1);
   frm->ShowModal();
   delete frm;
}


위와같은 폼 생성자를 만들어 컴파일하면 에러없이 실행됩니다.


하지만 위 생성자를 사용하여 Form을 새성하면 다음과 같은 에러가 납니다.



문제는?
위와같은 에러가 나는 이유가 무엇일가요?


그럼..







[수정 2012-04-05]
2년만에 글 내용을 첨언합니다.
갑자기 생각나서 ....

아래 강재호.만해 댓글을 보고 한번 테스트 해보니
2010에서는 정말 괜찮네요

예전엔 2010을 쓰지 않았었는데..
최근엔 C++Builder2010을 주 개발툴로 쓰고 있습니다.

그래서
vcl 소스를 보니 정말로 구조가 좀 바뀌어 있었습니다.

옛날 vcl소스에선
CustomForm.Create (생성자) 에서
CustomForm.CreateNew(다형성된 생성자) 를 호출하도록 되어있었습니다.

// C++Builder 6.0  VCL 소스   ,   TCustomForm의 생성자 
constructor TCustomForm.Create(AOwner: TComponent);
begin
  GlobalNameSpace.BeginWrite;
  try
    CreateNew(AOwner);     //Form생성자에서 CreateNew를 호출 
    if (ClassType <> TForm) and not (csDesigning in ComponentState) then
    begin
      Include(FFormState, fsCreating);
      try
        if not InitInheritedComponent(Self, TForm) then
          raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
      finally
        Exclude(FFormState, fsCreating);
      end;
      if OldCreateOrder then DoCreate;
    end;
  finally
    GlobalNameSpace.EndWrite;
  end;
end;


CustomForm.CreateNew의 파라메터가

다음 두개...  ( TComponent*  , int  ) 를 받습니다.
// // C++Builder 6.0  VCL 소스 
constructor TCustomForm.CreateNew(AOwner: TComponent; Dummy: Integer);
begin
  inherited Create(AOwner);
  // 생략
end;




2010의 VCL 소스는 바뀌었네요

{ TCustomForm }
//RadStudio2010 의 vcl 소스 
constructor TCustomForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner); //bcb6에선 CreateNew를 호출했었는데.. 2010에는 변경됨 
  // 생략 
end;




2009버젼은 정확히 잘 모르겠지만
2010부터는 위와같이 다형성을 해도 문제가 없네요

그럼..
강재호.만해 [greenuri]   2010-03-14 00:36 X
장성호님 2010에서 테스트 중인데요 안나는데요 ^^
장성호 [nasilso]   2010-03-14 19:18 X
위 코드는 bcb6에서 테스트 한것인데..
방금 C++Builder2007에서 테스트 했는데도 똑같네요


2010에서 구조가 바뀌었나?
회사에서 2010구매는 했는데
아직 설치해보질 못했서 테스트를 못해봤네요

Form 생성자 다형성이 안되는 경우는
생성자 파라메터가 (TComponent *  , int )
이렇게 딱 2개 순서도 똑같이 되어있는 경우 입니다.

혹 다르게 테스트 하신것은 아니신지요?

Frigate [devilica]   2010-03-14 23:14 X
저도 BCB6에서 테스트 했습니다. 역시 같은 에러가 나오는군요.

TForm의 상위 클래스인 TCustomForm을 찾아가 보니
생성자가 다음과 같이 되어 있었습니다.

    /* TCustomForm.Create */ inline __fastcall virtual TForm(Classes::TComponent* AOwner) : TCustomForm(AOwner) { }
    /* TCustomForm.CreateNew */ inline __fastcall virtual TForm(Classes::TComponent* AOwner, int Dummy) : TCustomForm(AOwner, Dummy) { }

두번째 생성자가 문제의 에러를 일으키는 생성자 입니다.
델파이에서 같은 방식으로 찾아들어가서 생성자를 비교해 보니

    constructor Create(AOwner: TComponent); override;
    constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); virtual;

위와같이 2개의 생성자가 있네요.
소스를 보니 첫번째 생성자(Create)호출시 두번째 생성자를 호출하도록 되어 있고. 두번째 생성자 호출시엔  첫번째 생성자를 호출하게 되어 있습니다.
첫번째 생성자는 폼(dfm)파일의 정보를 참조해서 폼을 생성하고, 두번째 생성자는 폼파일 정보 없이 디폴트값으로 초기화만 하도록 되어 있군요.

델파이에서도 BCB처럼 두번째 생성자를 오버라이드 해봤는데 이걸 컴파일러에서 막더군요.
[Error] Unit1.pas(26): Unsatisfied forward or external declaration: 'TForm1.CreateNew'

BCB에서는 두번째 생성자를 오버라이드 해 놓을경우 첫번째 생성자를 호출하면서 스택오버플로우 에러가 나더군요.
첫번째 생성자가 재귀호출되는것으로 보입니다.

여기까지가 제가 알아낸 전부 입니다만... 왜 스택오버플로우 에러가 나는지 모르겠네요. ㅠㅠ
장성호 [nasilso]   2010-03-14 23:33 X
와우~!
정답입니다.

TCustomForm.CreateNew 때문에 발생하는 것입니다.
TCustomForm.CreateNew 파라메터가 TComponnet * , int 이죠

TForm을 상속받은 폼에서 생성자를 다형성할때 파라메터가 (TComponent * , int ) 인 것이 있으면
TCustomForm의 CreateNew 생성자를 오버라이드 한결과를 낳게되는것입니다.

다음과 같은 TForm2생성자가 있다고 합니다.
__fastcall TForm2(TComponent* Owner,int iNumber)  
    : TForm(Owner)    //<<== 이부분
{  
    //
}

TForm2생성자에서 TForm(Owner)를 호출합니다.
이때 TCustomForm.Create(Onwer)를 호출되고
TCustomForm의 생성자 TCustomForm.Create에서
TCustomForm.CreateNew를 호출하는데..
이때 TCustomForm.CreateNew가 호출되는것이 아니라 TForm2에 override된 생성자가 호출되는것입니다.

TForm2에서는 다시 TForm(Owner)를 통해 TCustomForm.Create를 호출하니..
계속 뺑뺑이 돌면서 stack-overflow가 발생하게 되는것입니다.

Form2를 생성할때 다형성한 생성자를 호출하지 않더라도
위와같은 생성자가 있기만 하면  stack-overflow 가 발생하게 됩니다.


-----------------------------------------------------------------------

Frigate님 글에
TCustomForm.CreateNew 생성자가 어떤 목적으로 쓰이는지 설명해 두셨는데..
위 생성자를 이용하면 *.dfm 파일없이 코딩만등로 TForm 또는 TCustomForm을 상속받은
Form 클래스를 만들어 생성할수 있습니다.

아래 링크에...
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=736

그럼..

+ -

관련 글 리스트
966 [퀴즈] Form 생성자 다형성의 문제점 장성호 9005 2010/03/13
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.