C++ 초급 - 8. 객체지향 프로그래밍 (5 - C++11의 override와 final)

2025. 2. 22. 15:48프로그래밍 언어/C++

📌 8.5 C++11의 override와 final

C++11에서는 가상 함수 오버라이딩을 더 명확하고 안전하게 수행하기 위해 override 키워드와 final 키워드가 추가되었다.
이를 통해 컴파일러가 오버라이딩 오류를 검출할 수 있으며, 클래스나 함수의 상속 및 재정의를 제한할 수도 있다.


📌 1. override 키워드의 필요성

🔹 (1) override란?

  • 부모 클래스의 virtual 함수를 자식 클래스에서 재정의할 때 명확하게 표시하는 키워드.
  • 컴파일러가 오버라이딩 여부를 검사하므로 실수 방지 가능.
  • 부모 클래스에 해당 함수가 없으면 컴파일 오류 발생.

🔹 (2) override 없이 발생하는 문제

  • 부모 클래스의 가상 함수 이름을 잘못 입력하거나, 매개변수 리스트가 다르면 오버라이딩되지 않음.
  • 하지만, C++11 이전에는 이를 검출할 방법이 없었음.

💡 예제: override 없이 발생하는 실수

#include <iostream>

class Base {
public:
    virtual void showMessage() { std::cout << "Base 클래스" << std::endl; }
};

class Derived : public Base {
public:
    void showMessage(int x) { std::cout << "Derived 클래스" << std::endl; }  // ❌ 오버라이딩 아님 (매개변수 다름)
};

int main() {
    Base* obj = new Derived();
    obj->showMessage();  // ✅ "Base 클래스" (Derived의 함수가 호출되지 않음)

    delete obj;
    return 0;
}

🔹 출력 결과

Base 클래스

💡 설명

  • Derived 클래스의 showMessage(int x)는 부모 클래스의 showMessage()를 재정의하려 했지만, 매개변수가 다르므로 오버라이딩되지 않음.
  • 따라서 Base의 showMessage()가 호출됨.

🔹 (3) override를 사용한 올바른 오버라이딩

  • override를 사용하면 부모 클래스의 가상 함수가 정확히 존재하는지 컴파일러가 검사.
  • 만약 함수명이 다르거나 매개변수가 다르면 컴파일 오류 발생.

💡 예제: override 사용

#include <iostream>

class Base {
public:
    virtual void showMessage() { std::cout << "Base 클래스" << std::endl; }
};

class Derived : public Base {
public:
    void showMessage() override { std::cout << "Derived 클래스" << std::endl; }  // ✅ 올바른 오버라이딩
};

int main() {
    Base* obj = new Derived();
    obj->showMessage();  // ✅ "Derived 클래스" (정상적으로 오버라이딩됨)

    delete obj;
    return 0;
}

🔹 출력 결과

Derived 클래스

💡 설명

  • Derived의 showMessage()에서 override를 사용함으로써 부모 클래스의 함수와 정확히 일치하는지 확인 가능.
  • override가 없다면, 오타나 매개변수 차이로 인해 의도하지 않은 동작이 발생할 수도 있음.

🔹 (4) override 미사용 시 발생하는 컴파일 오류

💡 오류 예제

class Derived : public Base {
public:
    void showmessage() override { std::cout << "Derived 클래스" << std::endl; }  // ❌ 오타 발생 (Base 클래스에는 "showMessage" 존재)
};

🔹 컴파일 오류 메시지

error: ‘void Derived::showmessage()’ marked ‘override’, but does not override any member functions

💡 설명

  • override 키워드 덕분에 부모 클래스에 showMessage()가 존재하지 않으면 컴파일 오류 발생.
  • 실수를 미리 방지할 수 있음.

📌 2. final 키워드의 필요성

🔹 (1) final이란?

  • 더 이상 상속받거나, 오버라이딩할 수 없도록 제한하는 키워드.
  • 클래스에 사용하면 상속 금지,
    함수에 사용하면 오버라이딩 금지.

🔹 (2) final을 사용하여 상속 금지

  • final을 사용하면 특정 클래스를 더 이상 상속받지 못하게 설정 가능.

💡 예제: final을 사용하여 클래스 상속 금지

class Base final {  // ✅ 이 클래스를 상속받을 수 없음
public:
    void show() { std::cout << "Base 클래스" << std::endl; }
};

/*
class Derived : public Base {  // ❌ 오류 발생! (Base는 final 클래스)
};
*/

int main() {
    Base obj;
    obj.show();
    return 0;
}

🔹 컴파일 오류 발생

error: cannot derive from ‘Base’ as it has been declared ‘final’

💡 설명

  • class Base final로 선언하면 이 클래스를 상속받는 것이 불가능.
  • 특정 클래스를 더 이상 확장하지 않도록 제한할 때 사용.

🔹 (3) final을 사용하여 함수 재정의(오버라이딩) 금지

  • final을 사용하면 자식 클래스에서 특정 함수를 오버라이딩할 수 없도록 설정 가능.

💡 예제: final을 사용하여 함수 오버라이딩 금지

#include <iostream>

class Base {
public:
    virtual void showMessage() final { std::cout << "Base 클래스" << std::endl; }  // ✅ 이 함수는 더 이상 오버라이딩 불가
};

class Derived : public Base {
public:
    /*
    void showMessage() override {  // ❌ 오류 발생! (Base에서 final로 선언됨)
        std::cout << "Derived 클래스" << std::endl;
    }
    */
};

int main() {
    Base obj;
    obj.showMessage();
    return 0;
}

🔹 컴파일 오류 발생

error: virtual function ‘virtual void Derived::showMessage()’ overriding final function

💡 설명

  • showMessage()를 final로 선언하면 파생 클래스에서 오버라이딩할 수 없음.
  • 기능을 확장하지 못하도록 제한하고 싶을 때 사용.

📌 3. 정리

개념  설명
override 키워드 부모 클래스의 가상 함수를 정확히 오버라이딩했는지 검사
override의 필요성 오버라이딩 실수를 방지 (부모 클래스에 동일한 함수가 없으면 컴파일 오류 발생)
final 키워드 클래스나 함수의 상속 및 오버라이딩을 금지
클래스에 final 적용 class Derived final { ... }; → 이 클래스를 상속받을 수 없음
함수에 final 적용 void func() final; → 이 함수를 오버라이딩할 수 없음