MFC 구조 완전 정리: Document/View 패턴과 핵심 클래스 구조 이해하기
📌 MFC 구조가 헷갈린다면 이 글로 확실하게 정리해보세요!
처음 MFC를 접하면 무엇보다 그 복잡한 구조가 장벽처럼 느껴질 수 있습니다.
클래스는 너무 많고, 문서/뷰 구조는 낯설고, 이벤트 처리는 마법처럼 돌아가죠.
하지만 알고 보면 MFC는 일관된 아키텍처와 자동화된 프레임워크 구조 덕분에 윈도우 GUI 애플리케이션 개발을 쉽게 만들어주는 도구입니다.
이 글에서는 MFC의 기본 구조부터 핵심 동작 원리까지 차근차근 설명해드릴게요 😊
MFC는 Microsoft Foundation Class의 약자로, C++ 기반에서 GUI와 이벤트 처리를 손쉽게 할 수 있도록 도와주는 프레임워크입니다.
Visual Studio에서 기본 제공하는 마법사(Wizard)로 프로젝트를 생성하면 수많은 클래스가 자동으로 만들어지는데요,
그 구조를 이해하는 것이 곧 MFC 개발의 핵심이라고 할 수 있습니다.
이번 글에서는 Document/View 구조, 메시지 맵, 클래스 역할 등 MFC의 핵심 개념을 실전 예제와 함께 정리해드릴게요.
📋 목차
📂 MFC 프로젝트가 생성되면 생기는 기본 구조
Visual Studio에서 MFC 애플리케이션 프로젝트를 생성하면 다양한 파일과 클래스가 자동으로 생성됩니다.
이 구조는 MFC의 기본 아키텍처인 Document/View 패턴을 기반으로 구성되며, 클래스 간 역할이 명확히 나뉘어 있다는 특징이 있습니다.
프로젝트 구조를 이해하려면 각 클래스가 어떤 책임을 가지는지 먼저 파악하는 것이 좋습니다.
예를 들어, CWinApp은 애플리케이션의 전체 생명 주기를 관리하고,
CDocument은 데이터와 상태를 저장하며,
CView는 실제 화면에 UI를 렌더링합니다.
그리고 이 모든 것을 연결해주는 것이 프레임워크의 역할이죠.
- 🧱CWinApp: 애플리케이션 초기화 및 실행
- 📄CDocument: 내부 데이터와 상태 관리
- 👁️CView: 사용자에게 보여지는 UI 처리
// 주요 클래스 예시
MyApp.h → CWinApp 상속
MainFrm.h → CFrameWnd 상속
MyDoc.h → CDocument 상속
MyView.h → CView 상속
💎 핵심 포인트:
MFC 프로젝트는 처음부터 역할 분리와 구조화가 되어 있기 때문에, 각 클래스를 중심으로 흐름을 파악하는 것이 가장 빠른 이해 방법입니다.
📄 Document/View 아키텍처의 개념과 역할
MFC의 핵심 구조는 Document/View 아키텍처입니다.
이는 애플리케이션의 데이터와 UI를 분리하여 관리하는 구조로, 모델-뷰 개념과 유사합니다.
이 구조를 통해 데이터와 화면 출력 코드를 깔끔하게 분리할 수 있어, 유지보수나 기능 확장이 한결 수월해집니다.
Document는 내부 데이터를 저장하고, View는 그 데이터를 사용자에게 시각적으로 보여주는 역할을 합니다.
또한 이 구조는 MFC 프레임워크 내부에서 자동으로 연결되며, 메시지 기반 이벤트 시스템과도 잘 결합됩니다.
덕분에 사용자가 어떤 액션을 취하면 적절한 Document 또는 View 클래스가 이를 처리하게 되는 구조가 자연스럽게 형성됩니다.
- 📄CDocument 클래스는 데이터 상태를 보관
- 👁️CView 클래스는 데이터를 시각화하는 책임 담당
- 🔁Document와 View는 자동 연결되며 메시지를 통해 상호작용
💬 Document/View 구조는 같은 데이터를 여러 View에서 동시에 표현하거나, 하나의 View가 다른 데이터를 참조하도록 유연하게 확장할 수 있는 구조입니다.
// View에서 Document 접근 예시
void CMyView::OnDraw(CDC* pDC) {
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// Document의 데이터를 화면에 출력
CString text = pDoc->GetContent();
pDC->TextOut(10, 10, text);
}
💡 TIP: 하나의 Document에 여러 개의 View를 연결하면, 데이터는 하나지만 다양한 UI 표현을 동시에 구현할 수 있어 매우 유용합니다.
🎨 CView 클래스에서 화면을 그리는 방식
MFC에서 화면에 무언가를 출력하고 싶다면 CView 클래스가 중심이 됩니다.
이 클래스는 사용자에게 보이는 모든 시각적 요소를 담당하며, 실제 출력 처리는 OnDraw()라는 가상 함수 안에서 수행됩니다.
OnDraw 함수는 Windows가 WM_PAINT 메시지를 처리할 때 자동으로 호출되며, 개발자는 그 안에서 GDI(Graphics Device Interface)를 사용해 텍스트, 선, 도형 등을 출력합니다.
이를 통해 CDocument의 데이터를 기반으로 사용자가 시각적으로 이해할 수 있는 정보를 구성하는 것이죠.
- 🖼️OnDraw()는 모든 그리기 로직의 시작점
- 🧮텍스트, 이미지, 도형 등을 CDC 객체를 통해 출력
- 📦출력할 데이터는 보통 Document에서 가져옴
void CMyView::OnDraw(CDC* pDC) {
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CString content = pDoc->GetContent();
pDC->TextOutW(100, 100, content);
pDC->MoveTo(50, 150);
pDC->LineTo(250, 150);
}
💬 CView 클래스는 WM_PAINT 메시지를 자동으로 처리해주며, OnDraw 함수에만 집중하면 되기 때문에 직접 메시지를 다룰 필요가 없습니다.
💡 TIP: 복잡한 그래픽 출력을 구현할 때는 Double Buffering 기법을 적용해 화면 깜빡임 없이 자연스럽게 렌더링할 수 있습니다.
📬 메시지 맵과 이벤트 처리 흐름
MFC는 내부적으로 메시지 기반 아키텍처를 사용합니다.
즉, 사용자의 모든 입력(마우스 클릭, 키보드 입력 등)은 Windows 메시지로 처리되며, MFC는 이를 클래스에 연결해주는 메시지 맵 구조를 제공합니다.
메시지 맵은 BEGIN_MESSAGE_MAP 매크로로 시작하고, 각 메시지를 해당 멤버 함수와 연결해줍니다.
예를 들어 사용자가 버튼을 클릭했을 때 특정 함수를 호출하고 싶다면, 메시지 맵에 해당 메시지와 함수의 연결을 선언해주면 됩니다.
- 🔁Windows 메시지를 클래스의 멤버 함수로 매핑
- 📌메시지 맵 선언은 .cpp 파일 내부에서 이루어짐
- 🔨ON_COMMAND, ON_WM_ 등 다양한 매크로 사용 가능
// 메시지 맵 예시
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_MY_COMMAND, &CMyView::OnMyCommand)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
void CMyView::OnMyCommand() {
AfxMessageBox(_T("명령이 실행되었습니다."));
}
void CMyView::OnLButtonDown(UINT nFlags, CPoint point) {
AfxMessageBox(_T("마우스 왼쪽 버튼 클릭됨"));
}
💬 MFC는 메시지 테이블 기반으로 동작하기 때문에, 선언만 잘 해두면 복잡한 이벤트 흐름도 자연스럽게 연결됩니다.
💡 TIP: 자주 쓰는 메시지들은 ClassWizard 기능을 통해 자동 등록하면 훨씬 빠르게 작업할 수 있습니다.
🏗️ CWinApp과 프로그램 초기화의 관계
MFC 애플리케이션에서 프로그램의 시작점은 바로 CWinApp 클래스입니다.
이 클래스는 애플리케이션의 전반적인 생명주기를 관리하며, 프로그램이 시작될 때 InitInstance()를 통해 주요 초기화 작업이 이루어집니다.
CWinApp은 프레임 생성, 문서-뷰 연결, 메뉴와 리소스 초기화 등 거의 모든 기반 설정을 담당합니다.
즉, 사용자가 프로그램을 실행하면 가장 먼저 이 클래스가 동작하며,
그 안에서 프레임윈도우(CMainFrame), Document, View 객체가 생성되고 연결되는 구조입니다.
- ⚙️InitInstance()는 프로그램 시작 시 호출됨
- 🏗️Document/View와 프레임 생성 및 연결 역할 수행
- 🧩App 클래스는 전역 객체로 선언되어 main 역할 수행
// MyApp.cpp
BOOL CMyApp::InitInstance() {
CWinApp::InitInstance();
// 문서 템플릿 생성
CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
// 새 프레임 열기
CFrameWnd* pFrame = pDocTemplate->CreateNewFrame(NULL, NULL);
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
💬 InitInstance 함수는 MFC 프로젝트의 핵심 진입점이며, 이 함수가 실행되어야 창이 뜨고 사용자가 프로그램을 사용할 수 있게 됩니다.
💡 TIP: App 클래스는 보통 전역으로 선언되기 때문에 따로 main()을 작성하지 않아도 MFC 애플리케이션이 자동으로 실행됩니다.
❓ 자주 묻는 질문 (FAQ)
MFC 프로젝트를 처음 만들면 왜 클래스가 이렇게 많나요?
Document/View 구조를 꼭 사용해야 하나요?
OnDraw에서 그린 화면은 언제 다시 그려지나요?
메시지 맵은 꼭 사용해야 하나요?
CWinApp은 프로그램 내에서 어떤 위치에 있나요?
InitInstance 함수는 언제 호출되나요?
MFC는 아직도 현업에서 사용되나요?
MFC와 .NET의 가장 큰 차이는 무엇인가요?
🧠 MFC 기본 구조를 이해하면 개발이 쉬워집니다
이번 글에서는 MFC(Microsoft Foundation Class)의 핵심 구조를 중심으로, 처음 접하는 개발자도 쉽게 이해할 수 있도록 설명드렸습니다.
MFC 프로젝트를 생성했을 때 등장하는 CWinApp, CDocument, CView, 프레임윈도우 등 주요 클래스의 역할과 연결 관계를 확인해보았고,
Document/View 아키텍처가 어떤 구조로 작동하는지도 단계별로 정리해보았습니다.
또한 메시지 맵을 통해 이벤트가 처리되는 방식, OnDraw 함수 내에서 GDI를 활용한 출력 처리 방식, 그리고 InitInstance에서 프로그램이 어떻게 시작되는지까지 살펴보며
MFC 구조의 흐름을 전반적으로 파악해보았습니다.
이제 여러분도 생성된 파일들을 단순히 ‘마법사 코드’로 보지 않고, 명확한 책임과 역할로 이해하실 수 있을 거예요 😊
🏷️ 관련 태그:MFC기초, CWinApp구조, DocumentView패턴, 메시지맵, MFC프레임워크, MFC초보, InitInstance, VisualStudioMFC, CView사용법, CDocument이해