삽질의 현장/- MFC

#001_MFC_Intro

shovelman 2015. 10. 15. 16:58


안녕하세요 삽잡이입니다.


이번시간부터는 MFC에 대해서 알아보려고 합니다.


MFC는 OS즉, Windows 위에서 동작하는 라이브러리입니다.

.Net 이 등장하기 전까지는 Window 계열에서 

가장 강력했던 언어라고 부르기는 뭐하지만... 뭐 언어였습니다...

이제 곧 역사속으로 사라질 수도 있을 MFC... 허허... 뭐 미래는 모르져...

아무튼... Visual C++ 안에 있는 라이브러리 중 하나가 바로 'MFC'입니다.



OS위에 API 라이브러리가 있고, 이 API 라이브러리를 통해 MFC가 만들어졌습니다.

따라서 MFC는 자신만의 라이브러리를 가지고 있지 않고, API를 100% 사용합니다.

이것이 한계이지요...

API는 함수 집합입니다. 즉, 라이브러리가 함수 단위로 만들어진 집합 말입니다.

이걸 관련성있게 모으고 재사용 할 수 있도록 클래스화 시켜놓은 것이 바로 MFC 입니다.


.Net을 띄우고 있는 지금 현재 왜 MFC를 알아야할까요...

맞습니다... 꼭 알아야할까요...


MFC가 지향했던 것이 FrameWork 프로그램입니다. 

프레임워크란, 우리말로 뼈대입니다.

즉, 프레임워크 프로그램은 뼈대가 있는 프로그램이라는 소리죠...

기반을 다지고 그 기반에 살을 붙여나가는 프로그램이 바로 프레임워크 프로그램이라는 것입니다.


이 MFC는 세계적으로 똑똑한 설계자들과 개발자들이

객체지향에 입각해서 어떤식으로 개발하는 것이 좋다는 이런 지침서(?)를 만들어 놨습니다.

즉, 틀로 짜놨다 이겁니다. 다른 말로... 역할 담당을 구조로 나타냈다 이거죠...

MFC는 그래서 범용적인 틀을 가지고 있다고 할 수 있습니다.

또한, MFC는 이미 구조로 만들어놓았기 때문에 진입장벽이 높다는 소리도 많이 듣는다고 합니다.

아무튼... MFC를 통해 개념을 공부하고 나면 

프레임워크에 대해 공부를 할 때 조금은 더 수월해지지 않을까요...


아무튼... 지금부터 Visual C++ 라이브러리인 MFC에 대해서 알아보겠습니다.


MFC는 Visual Studio에서 생성시켜보면 알겠지만,

뼈대를 만들어주는 작업을 우선 수행합니다.

즉, 기본적인 클래스와 메소드를 만들고 이를 MFC 프레임 워크라고 부른다는 소리입니다.

이 MFC 프레임워크에 참여한 클래스들을 우리는 MFC 프레임워크 클래스라고 부릅니다.



프로그램은 보이는 영역과 보이지 않는 영역으로 나뉠 수 있습니다.

보이는 영역은 UI라고 하며 Window라고도 부릅니다.

이 영역은 사용자와 이야기를 하는 부분이지요...

보이지 않는 영역에는 데이터와 실행이 속해있습니다.


데이터를 보여주는 영역이 UI 영역인데,

UI는 작업 영역과 비 작업 영역으로 나뉠 수 있습니다.

이 때에 비작업 영역을 표현하기 위한 영역을 Frame이라고 말합니다.

이 Frame을 추상화 한 것이 바로 'CFrameWnd' 클래스 입니다.

이 CFrameWnd 클래스를 통해 객체 생성을 하여야 프레임 창이 만들어집니다.


작업영역을 일반적으로 View라고 부릅니다.

그리고 이 작업을 추상화 한 것이 바로 'CView' 클래스입니다.


또한 실행 시켜주는 역할하는 클래스를 'CWinApp'클래스가 담당합니다.

이 클래스를 통해 객체를 생성해야지 Window Class를 등록 시켜서 프로세스를 동작시킬 수 있습니다.

왜냐하면, thread의 기능을 상속받기 때문입니다.

실질적으로 프로그램을 동작하도록 하는 역할이 이 CWinApp 클래스에 들어가있다 이소리입니다.

쉽게 생각하자면, 실행하는 객체를 관리하고, 요소를 관리하고, 실행을 제어해줍니다...


또한, 프로세스의 동작 및 처리를 맡아서 주관해줍니다.

그리고 Main 윈도우를 생성해줍니다.


데이터를 보관하고 처리하기 위해 만든 클래스는 'CDocument'클래스입니다.


더 있을 수 있으나 이렇게 네가지의 클래스가 주요 프레임워크에 포함됩니다.


우리가 보는 화면에는

CFrameWnd(넌 클라이언트 영역)과 Cview(클라이언트 영역) 이 둘이 보일 것입니다.

이 둘은 사실 CWnd 클래스를 상속받아서 생겼습니다.


아무튼... 이렇게 MFC 프레임워크에는 클래스들을 나누어 역할을 담당합니다.


어디에든 데이터를 보관해도 상관없습니다.

하지만, CDocument 클래스의 객체에 보관하는 것이 좋습니다.

즉, 보여지는 영역의 메소드에 데이터를 보관해도 좋지만,

보여주지 않는 CDocument 클래스의 객체에 보관하는 것이 좋다는 소리입니다.


MFC는 객체지향 프로그램입니다.

그리고 클래스는 단지 기능에 대한 정의를 한 덩어리일 뿐입니다.

기능에 대한 정의만 했을 뿐이지 프로그램 실행 때에는 클래스와 관련이 있다는 것이 아니란 소리입니다.

실행 될 때에는 클래스의 객체가 만들어지고 객체들이 활동하는 것이지요...

정의를 클래스의 메소드에 해놓지만 실행되면 클래스는 정의일 뿐, 객체가 실질적인 역할을 담당합니다.


따라서 프로그램이 실행될 때에는 한 클래스의 객체들이 여러개 만들어질 수 있습니다.

그런데, CWinAPP의 객체는 단 하나만 만들어집니다.

실행을 시켜주는 역할을 여러개의 객체가 할 수 없기 때문입니다.

그 어떤 객체보다도 가장 먼저 오직! 최초에 하나 만들어집니다.



이 CWinAPP으로 부터 생성된 객체(편의상 APP)는 3개의 객체를 만들어냅니다.

APP에 의해서 프로그램이 시작될 때 내부적으로 new 연산을 통해 생성이 되는 것입니다.

바로 CFrameWnd 클래스로부터 생성된 CMainFrame 객체와

CView 객체, CDocument 객체를 만들지요...

그리고 View 객체와 Document 객체는 꼭 한쌍을 이루고 있습니다.


그리고 APP객체가 하나 만들어지게 되면 Main Frame도 하나 생성됩니다.

왜냐하면, Main 프로그램을 관장하는 넌 클라이언트 윈도우이기 때문입니다.


정리하자면,

APP과 MainFramework는 오직 하나 만들어집니다.

View와 Document는 여러개 만들어질 수 있지요...

그런데 만약, 단일 Document로 만들어진 프로그램이라면 Document도 하나만 생성됩니다.

멀티 Document라면 여러 대의 Document도 만들 수있습니다.

하지만, View는 n개 .. 즉, 여러개를 만들 수 있습니다.


이들은 독립적인 객체로써 멤버변수를 사용합니다.

메모리 영역에서 표현하자면, View, Document와 같은 객체들은 Heap 영역에,

이 객체들 안에 멤버 변수 및 함수들은 Stack 영역에 만들어진다는 것입니다.

WM_LBUTTONDOWN 이나 WM_PAINT와 같은 윈도우 메시지들은 

코드 영역에 자리를 잡습니다.


클래스와 객체를 같게 생각하면 안됩니다.

클래스는 데이터정의, 명령 정의, 실행 정의이고 

실제 프로그램이 동작할 때에는 객체화가 되서 객체가 생성되고 

데이터가 객체화 되고... 모두 명령이 되는 것이지요...


MFC의 Main코드는 감춰져 있습니다. 

CWinAPP으로 부터 객체가 생성되면서 위에서 언급했던 

Window Class 생성 및 초기화, 메시지 루프, 등 Main 코드들을 실행시키기 때문입니다.


따라서, Main 코드로써 InitInstance() 를 호출하여 생성 및 초기화를 하고,

내부적으로 Run() 함수를 통해 실행, 

그리고 종료시 ExitInstance() 함수를 호출하여 마무리를 합니다.


이 중 Run() 함수는 자동으로 알아서 수행을 시키는 것입니다.

작업이 자동으로 처리가 되는 이유는 

수동으로 작업 실행 시 오류가 날 가능성이 높고 불편하기 때문입니다.

물론, 수동으로 작업 처리를 할 수 있긴 합니다...


이 셋 함수는 매우 중요합니다.

생성 및 초기화, 실행, 소멸을 담당하니깐요...

이 Run() 함수는 핵심적인 함수입니다. 

왜냐하면, 메시지 펌핑, 디스패치를 시켜주는 함수이기 때문이죠...

즉, 메시지 큐에서 메시지를 읽어와 디스패치시키는 역할을 한다 이겁니다.


만약, 재정의를 통해 Run() 함수를 밖으로 꺼내오게 되면

오버라이드가 되었기 때문에 객체가 만들어집니다.

따라서 Run 함수는 내 것이 호출 되겠지요...



여기서 'CWinAppEx::Run()' 문장은 부모 클래스를 호출시키려고 사용한 것입니다.

왜냐, API에서 DefWindowProc() 함수를 생각해보세요...

메시지 처리를 하고 디폴트 처리를 부모에게 맡겼습니다.

즉, 디폴트 적인 부가작업을 하기 때문에 부모 함수를 호출 시키는 것입니다.



이번 시간에는 략하게(?) MFC 구조의 흐름, MFC의 주요 클래스들에 대해서 알아봤습니다.

이상 삽잡이였습니다!




'삽질의 현장 > - MFC' 카테고리의 다른 글

#006_MFC_Control, Value형 변수  (0) 2015.10.19
#005_MFC_Document Template 설명  (0) 2015.10.19
#004_MFC_동적 배열 CArray 설명  (0) 2015.10.19
#003_MFC_메모리의 구성  (0) 2015.10.16
#002_MFC_View (기본적인 입출력)  (0) 2015.10.15