티스토리 뷰

728x90
반응형
C++ 상속 설계의 정석: final과 override를 써야 하는 이유

상속 설계의 정석: "상속이 필요 없으면 final을, 한다면 override를"

C++ 개발 시 가장 빈번하게 발생하는 실수는 '의도하지 않은 상속''잘못된 재정의'입니다. 컴파일러가 내 실수를 대신 찾아내게 만드는 똑똑한 키워드 활용법을 예제와 함께 알아봅니다.

1. override: 컴파일러에게 감시 요청하기

단순히 부모 함수와 이름을 맞추는 것만으로는 부족합니다. override는 실수를 에러로 바꿔주는 안전장치입니다.

❌ override가 없는 위험한 코드

class Base {
public:
    virtual void process(float speed) { ... }
};

class Derived : public Base {
public:
    // 개발자의 실수: float인데 double로 작성함
    void process(double speed) { ... } 
    // 컴파일러는 새로운 함수가 추가된 줄 알고 조용히 넘어갑니다. (버그 발생!)
};

✅ override를 사용한 안전한 코드

class Derived : public Base {
public:
    // 컴파일 에러 발생: "Base에 double을 받는 process가 없는데?"
    void process(double speed) override { ... } 
};

2. final: 상속의 마침표 찍기

클래스 설계의 본질은 '필요한 곳에만 상속을 허용'하는 것입니다. 더 이상 자식이 필요 없는 완성된 클래스에는 final을 붙여 문을 닫으세요.

상속은 받되, 자식은 거부하는 패턴

// 부모로부터 기능을 물려받지만
class PacketAnalyzer final : public ProtocolBase {
public:
    // 이 분석 로직은 여기서 완성됨 (재정의 금지)
    void analyze() override final { ... } 
};

// class CustomAnalyzer : public PacketAnalyzer { }; // ERROR!

3. 가상 소멸자 vs 일반 소멸자 (final의 위력)

상속 관계에서 부모 소멸자에 virtual이 없으면 자식 객체의 메모리가 해제되지 않습니다. 하지만 final 클래스라면 고민할 필요가 없습니다.

상황별 소멸자 가이드 예제

// [Case 1] 상속용 부모 클래스: virtual 소멸자 필수!
class Parent {
public:
    virtual ~Parent() { ... }
};

// [Case 2] 상속이 금지된 final 클래스: virtual이 없어도 무방(성능 우위)
class TokenStore final {
public:
    ~TokenStore() { /* 메모리 누수 위험 없음 */ }
};

4. 종합 예제: 실무형 클래스 설계

지금까지 배운 키워드를 모두 활용한 실제 패킷 처리 시스템의 구조입니다.

class BaseParser {
public:
    virtual ~BaseParser() {} // 상속용이므로 가상 소멸자
    virtual void parse() = 0; // 순수 가상 함수
};

// 설계 의도: 이 클래스는 상속을 통해 확장하지 마시오.
class TcpParser final : public BaseParser {
public:
    // 1. 부모의 함수를 정확히 재정의함을 명시
    // 2. 이후 자식이 없으므로 여기서 더 이상의 override도 금지
    void parse() override final {
        // TCP 데이터 분석 로직...
    }

    // final 클래스이므로 소멸자에 virtual을 붙이지 않아도 안전함
    ~TcpParser() { }
};

🚀 블로그 요약 가이드

  • virtual: 부모가 자식에게 "너가 바꿔 써도 돼"라고 허락하는 문입니다.
  • override: 자식이 부모의 문을 "정확히 찾았다"고 컴파일러에게 알리는 신호입니다.
  • final: "이 클래스는 완벽하니 더 이상의 상속과 변형을 금지한다"는 선언입니다.
  • 컴파일러 활용: 실수(Runtime Error)를 빌드 에러(Compile Error)로 바꾸는 것이 고수의 설계입니다.
728x90
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
글 보관함