C++ 예제로 배우는 소프트웨어 설계 기법 (5) — 도형 편집기(Shape)
사각형, 원, 삼각형을 그리고 복사·붙여넣기하고 파일에서 다시 읽어 들이는 도형 편집기는 객체지향 설계를 연습하는 고전적인 예제다. 도형 종류를 값으로 구분해 switch로 처리하면 새 도형을 추가할 때마다 흩어진 switch를 모두 찾아…
사각형, 원, 삼각형을 그리고 복사·붙여넣기하고 파일에서 다시 읽어 들이는 도형 편집기는 객체지향 설계를 연습하는 고전적인 예제다. 도형 종류를 값으로 구분해 switch로 처리하면 새 도형을 추가할 때마다 흩어진 switch를 모두 찾아…
설정, 로거, 입력 장치처럼 프로그램 전체에 하나만 있어야 하는 객체가 있다. 전역 변수로 두면 누구나 새로 만들 수 있고, 생성 시점도 통제할 수 없다. 싱글톤(Singleton)은 생성자를 막고 정적 접근 함수…
Win32 SetTimer 같은 C 타이머 API는 콜백에 타이머 id만 넘겨준다. 시계 객체 여러 개가 각자 타이머를 걸면, static 콜백 안에서는 어느 객체의 타이머가 울렸는지 알 수 없다. 1편의 Thread는 void*로…
pthread_create 같은 OS 스레드 API는 void* (*)(void*) 형태의 C 함수 포인터만 받는다. 스레드에서 객체의 멤버 함수를 돌리고 싶어도 그대로 넘길 수 없다. 그래서 C 콜백 API를 클래스로 감싸는 첫 단계가…
지난 글에서 dynamic_cast는 상속 그래프를 탐색하느라 typeid 비교보다 10배 넘게 느렸고, -fno-rtti로 빌드하면 아예 쓸 수 없었다. 그래서 LLVM/Clang처럼 타입 판정이 잦고 -fno-rtti로 빌드하는 프로젝트는 RTTI를 직접 구현한다. 각 객체에…
기반 클래스 포인터만 들고 있는데 실제 객체가 어떤 타입인지 알아야 할 때가 있다. 이벤트 큐에서 꺼낸 객체를 타입별 핸들러로 보내거나, 특정 파생 타입에만 있는 기능을 쓰는 경우다. C++은 실행 시점…
Java나 C#에는 interface 키워드가 있지만 C++에는 없다. 대신 데이터 멤버 없이 순수 가상 함수와 가상 소멸자만 가진 추상 클래스를 인터페이스로 쓴다. 인터페이스를 두면 코드가 구체 클래스 대신 "이런 동작을 할…
도형마다 넓이를 계산하는 방법은 다르지만, "도형"이라는 객체 자체는 넓이를 정할 방법이 없다. 그렇다고 Shape::area()가 0을 반환하게 두면 파생 클래스가 재정의를 빠뜨려도 조용히 0이 나온다. 순수 가상 함수(pure virtual function) =…
Base* p = new Derived; delete p;는 컴파일도 실행도 문제없어 보인다. 하지만 Base의 소멸자가 가상이 아니면 delete는 정적 타입 Base의 소멸자만 호출한다. Derived가 잡은 자원은 해제되지 않고, 표준상으로는 미정의 동작이다.…