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
[952] [퀴즈] 다음 코드에 문제점을 찾아보세요
장성호 [nasilso] 7963 읽음    2010-02-24 01:01
[퀴즈] 다음 코드에 문제점을 찾아보세요


볼포/델마당 등 커뮤니티에 올라오는 질문의 소스를 보노라면...
다음과 같은 소스를 자주 보게 됩니다.

다음 코드에 어떤 문제가 있을까요?



//C++Builder
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    Form1->Caption="Title";
}
void __fastcall TForm1::FormShow(TObject *Sender)
{
    Form1->Left=0;
    Form1->Top=0;
}
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    Form1->BringToFront();
}



//Delphi
procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Caption:='Title';
end;
procedure TForm1.FormShow(Sender: TObject);
begin
    Form1.Left:=0;
    Form1.Top:=0;
end;



많은 경우에 전혀 문제가 되지 않을수도 있지만..

여러가지 위험성을 포함한 코드로 보이네요~!

..
Lyn [tohnokanna]   2010-02-24 01:09 X
Form1 -> this(self)
박지훈.임프 [cbuilder]   2010-02-24 01:41 X
초급자들이 가장 흔하게 하는 실수이고, 또 일단 이 실수는 하고 나면 대체로 원인을 찾기도 어렵죠.
Form1을 자연스럽게 써놨다는 것은 문제를 모른다는 얘기고, 그러면 에러가 발생했을 때 스스로는 거의 해결이 어렵죠.

바로 어제도 제가 초급자 과정 진행중인 대학생들에게 잠깐 짬을 내어 설명했었답니다.
이경문 [gilgil]   2010-02-24 12:55 X
델파이 컴포넌트에 의해 발생하는 이벤트가 아니라, System Callback에 의해 발생하는 함수는 일반적으로 static하게 설정을 하거나 일반 함수의 형태로 되어 있는데, 이 경우 Form1 객체 포인터가 Stack에 의해서 넘어 오지 않는다면, 부득이하게 코드상으로 Form1 객체를 명시하는 경우가 있습니다. Form1 객체의 존재를 확인하는 코드를 집어 넣는 것이 정석인데, 음... 귀찮아서리... ㅠㅠ
박영목.월천 [gsbsoft]   2010-04-07 18:37 X
헉... 저는 아직 초보라 제법 그런 코드가 들어가 있는 데... 역시 정석으로 안배우니 그런 모양입니다. 그렇다면...

void __fastcall TForm1::FormShow(TObject *Sender)  
{  
    Form1->Left=0;  
    Form1->Top=0;  


요것은 this->****   이렇게 하면 되는 데...


아래 이놈은 어떻게... Form1-> 안사용하고... 어떻게 하지요....  메세지를 보내려고 해도... Form1->Handle을 해야 하고...    이것 파이프나... LAN로 보내어야 합니까?     퀴즈는 어려워.... 답도 정확하게 가르쳐 주세요 ^^

void __fastcall TForm2::Button1Click(TObject *Sender)  
{  
    Form1->BringToFront();  
장성호 [nasilso]   2010-04-07 21:54 X
이 퀴즈(팁)은?
Form1 이나 Form2등 CBuilder, Delphi에서 자동생성하는 전역변수를 쓸경우의
발생하는 문제점에 대해 지적한 것인데요..


Form2에서 Form1에 접근하고자 하는 것은 또다른 문제점이 있습니다.
소스코드가 서로 의존적이게 되죠

Form1유닛을 수정하게되면  Form2 유닛도 컴파일 다시해야하는 문제가 있죠

------------------------------------------------------------------------
Form2에서 Form1에 접근하는 방법은 엄청 여러가지가 많은데요..
몇가지만 얘기하면

방법1.
  //Form1이 메인폼인경우에..
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    Application->MainForm->BringToFront();
}
//---------------------------------------------------------------------------

방법2. Screen객체를 이용하여..
void __fastcall TForm2::Button2Click(TObject *Sender)
{
    for(int i=0;i<Screen->FormCount;i++)
    {
        if(Screen->Forms[i]->Name=="Form1")
        {
            Screen->Forms[i]->BringToFront();
        }
    }
}
//---------------------------------------------------------------------------

방법3. Form1에서 Form2를 Show 할때 Form1 객체를 넘겨받아 멤버로 설정해 두는 방법
void __fastcall TForm2::SetCtrlForm(TForm *frm)
{
    m_Form=frm;
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button3Click(TObject *Sender)
{
    if(m_Form)m_Form->BringToFront();
}
//---------------------------------------------------------------------------

방법4. CallBack함수를 이용하는 방법..
     Form1에서 Form2를 Show할때 Form2에다가 Form1의 method를 넘겨줍니다.

#include "Unit2.h"
void __fastcall TForm1::SetFormPos()
{
    this->BringToFront();
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TForm2 *frm2=new TForm2(this)
    frm2->SetFormPosFunc(SetFormPos);
    frm2->Show();
}
//======================================================
void __fastcall TForm2::SetFormPosFunc(TSetFormPos func)
{
    m_SetFormFunc=func;
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button4Click(TObject *Sender)
{
    if(m_SetFormFunc)m_SetFormFunc();
}
//---------------------------------------------------------------------------

위와같이 Form1의 메소드를 호출하여서 처리합니다.
Form1의 멤버에 접근하려면 함수를 넘겨주는게 좋겠죠..


그밖에 Form2의 Owner가 Form1이면 Owner를 이용한 방법도 있을것이구..
다양한 방법이 있을것입니다.

가능하면 의존성을 떨어뜨리면 컴파일 속도도 빨라지고..
나중에 프로그램 수정 변경할때..
관련 모듈을 다른 프로젝트에 가져다 쓸때 등등..

여러가지로 좋습니다.

------------------------------------------------------------------------------
앗참 위 문제의 답변중에 한가지는
vcl객체 생성방법퀴즈와도 연관이 되어있는데용..
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=954

Form2객체를 생성할때 Form2=new TForm2(Application); 이렇게 생성하면
Form2의 OnCreate이벤트에 아직 Form2변수에는 쓰레기값이 들어있습니다.

Applicaion->CreateForm을 생성하면 그렇지 않구요..

그럼..
박영목.월천 [gsbsoft]   2010-04-08 01:51 X
   장성호님 감사요 ^^.....................................................................................

    for(int i=0;i<Screen->FormCount;i++)
    {
        if(Screen->Forms[i]->Name=="Form1")
        {
            Screen->Forms[i]->BringToFront();
        }
    }

    위의 것은 다른 폼이 다 생성되었는지... 검사하고 시작할 때... 좋을 것 같습니다 ^^
    혹 몇년 전에  덩치가 아주 큰 놈을 만들었는 데... 한번씩... 별 것 아니지만...
    Error 창이 뜨더군요... 시작할 때 15번 정도 하면 1번 정도... 느린 PC는 더 뜨고....
    그리고 본격적으로 시작하기 전... 시간을 더 주어도 뜰 때가 있었습니다...
    그냥 클릭만 한번 하면 지나갔고.. 돌아가는 데는 문제가 없어서... 찾기도 힘들고...
    내버려두었는 데... 아직도 마음에 걸립니다.

    느낌으로 다른 폼들이 다 생성되지 않은 상태에서 접근을 해서 그런 것으로 알고
    있습니다.
    ( 프로그램이 겉으로 매끄럽게 인터페이스가 되게 하려면 거미줄 처럼 서로 엉키지
     않으면 좀 처럼 되지 않더군요... 여하튼 서로 많이 엉키는 편입니다. 사용자를 위해)
   
    저 놈으로 검사하고 주요 메인폼들이 다 떴는지 확인하고 들어가면 괜찮을 것 같은 데...
    언젠가 함 TEST를 해봐야 할 것 같습니다.

   
    다른 것은 접근하는 것이 TForm의 public에 있는 변수나 함수를 접근하는 것은 되는 데...
    TMyForm으로 만들었다.  그러면 MyForm에서 만든 public 으로 선언된 것 다 접근할 수
    있는데...   사실 이런 것 접근이 실제적인 코딩에서 더 많지요.   어떻게 MyForm을 알아
    내었다고 해도 (TMyForm*) 이렇게 변환해서 알아내어야 할 것 같은 데...
    그러면 TMyForm의 헤드파일이 포함되어야 할 것이고... MyForm의 Header 파일을 수정
    하면 연관된 Form들 다 다시 컴파일 하겠지요.  다시 컴파일 하는 것은 자동생성 해주는
    Form명을 사용할 때와 같을 것입니다... 이것은 유연성 있는 프로그램을 만들기 위해 기쁜
    마음으로 참을 수 있습니다.

    그렇다면... 계속 빌더에서 자동 생성해 주는  전역변수 Form명을 사용할 경우  발생할 수
    있는 문제... 처음 시작할 때....   Screen->Forms[i]->Name=="Form1" 이런 식으로
    주요 서로 연관된 폼이 다 떳는지 확인하고 시작했을 때....  자동 생성되는 Form명을 사용
    했을 때...

    부작용은 무엇인지?  있다면 어떻게 대처하면 되는지...  일반적인 프로그래머가 자동생성해
    주는 Form을 사용할 것을  C++Builder를 만든 개발자들도 알 것인 데...  저렇게 노출을
    시켜두고  고의적인 방관을 했을까?  하는 생각이 떠오릅니다.


    바로 사용했을 때... 부작용 부탁드립니다 ^^

    ( 메인에서 Screen->Forms[i]->Name=="Form1"  이렇게 주요폼들을 다 검사하고 기다
      리다가 시작했을 때...)

박영목.월천 [gsbsoft]   2010-04-08 17:50 X
답이 없어서... 직접... 네이트로 문의... 장성호님과의 대화...

----- 장성호님
원문에 많은경우 전혀 문제가 되지 않을수 있다고 써놓았는데요..
저렇게 사용하다가 문제가 발생해서 델마당이나 포럼에
문제를 못찾아 질문이 올라오는 경우가 상당히 많더구요
동적생성하면서.. 저 전역변수에 객체가 할당되어있다고 착각하거나

----- 장성호님
두개 이상객체를 생성할경우 엉뚱한 객체에 접근하거나..

----- 박영목
OK...

----- 장성호님
모든 폼을 딱 하나만 생성하고
모두다 Auto-Create를 쓰면 거의 문제가 발생하지 않습니다.

----- 박영목
거의 문제가 없는 데... 오해요지 있다..

----- 박영목
그런데 
AutoCreate가 뭡니까

----- 박영목
용어를 잘 몰라서

----- 장성호님
프로젝트 옵션에 Auto-Create라는 부분이 있는데요..

----- 박영목
아... 예...

----- 장성호님
옵션의 Forms탭에
Auto-Cateate Forms 란는곳에요

그려면 Prorject xxx.cpp에서

WinMain에서
Application->Run() 호출하기전에

Application->CreateForm으로 폼을 생성하느 코드가 자동 생성됩니다.

----- 박영목
프로그램 실행될 떄 폼을 다 만들어 두는 것..

----- 박영목
나는 중요폼은 다 저렇게 사용했는 데....

----- 박영목
OK 그러면 괜찮겠네..

----- 박영목
그러면 옛날 일어난 것은 다른 문제였던 모양입니다.

----- 박영목
시스템을 많이 건드리는 것이라...

----- 박영목
마음 놓았습니다..
----- 박영목

----- 박영목
ㅋㅋㅋ 감사합니다...

----- 박영목
정리해서 댓글에 달아 두어야겠다...

----- 박영목
그럼 다음에... 또...

----- 장성호님
아뇨 무슨....

퀴즈내고.. 댓글을 통해 저도 많이 공부하고 있습니다.

----- 박영목
감사....^^

( 아래는 사적인 것이라 생략했습니다 )
박영목.월천 [gsbsoft]   2010-04-08 17:54 X
혹 한번씩.... 폼을 만들고 동적 생성하면 이상하게 Error 나는 폼이 있더라구요...  그런 것은 Auto-Create로 처리해 버립니다...   원인도 잘 모르겠고...  여하튼...

+ -

관련 글 리스트
952 [퀴즈] 다음 코드에 문제점을 찾아보세요 장성호 7963 2010/02/24
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.