C++에서 override 키워드는 객체 지향 프로그래밍의 핵심 개념인 다형성(polymorphism)을 구현할 때 매우 유용한 도구입니다. 이 글에서는 override 키워드가 무엇인지, 어떤 문제를 예방해 주는지, 그리고 실제 코드에서 어떻게 활용되는지 자세히 알아보겠습니다.
override 키워드란?
override 키워드는 파생 클래스(자식 클래스)가 기반 클래스(부모 클래스)의 가상 함수(virtual function)를 재정의한다는 것을 컴파일러에게 명시적으로 알려주는 역할을 합니다.
만약 함수 시그니처(함수 이름, 매개변수, 반환 타입)가 기반 클래스의 가상 함수와 일치하지 않으면, 컴파일러가 오류를 발생시켜 개발자가 실수를 조기에 발견할 수 있도록 도와줍니다.
override 없이 발생하는 문제
다음 예제를 살펴보겠습니다. 파생 클래스에서 기반 클래스의 함수와 이름은 같지만 매개변수가 다른 함수를 정의하면 어떻게 될까요?
#include <iostream>
using namespace std;
class Base {
public:
// 재정의될 가상 함수
virtual void func() {
cout << "I am in base" << endl;
}
};
class Derived : public Base {
public:
void func(int a) { // 오버로딩처럼 보이지만, 사실은 기반 클래스 함수를 숨김(hiding)
cout << "I am in derived class" << endl;
}
};
int main() {
Base b;
Derived d;
d.func(6);
return 0;
}실행 결과:
I am in derived class
이 코드는 정상적으로 컴파일되고 실행되지만, 개발자의 의도와 다르게 동작할 위험이 있습니다. 파생 클래스의 func(int a)는 기반 클래스의 func()를 재정의한 것이 아니라 함수 숨김(function hiding)이 일어난 것입니다. 즉, d.func()처럼 인자 없이 호출하면 컴파일 오류가 발생합니다.
override 키워드로 안전하게 해결하기
여기에 override 키워드를 추가하면 상황이 달라집니다.
class Derived : public Base {
public:
void func(int a) override { // 컴파일 오류 발생!
cout << "I am in derived class" << endl;
}
};컴파일러는 "기반 클래스에 func(int)라는 가상 함수가 존재하지 않는다"는 오류 메시지를 출력하여, 개발자가 의도치 않게 함수 시그니처를 잘못 작성했음을 즉시 알려줍니다.
올바른 재정의 예제
class Derived : public Base {
public:
void func() override { // 정상적으로 재정의됨
cout << "I am in derived class" << endl;
}
};override 키워드 사용의 장점
- 실수 조기 발견: 함수 시그니처가 일치하지 않으면 컴파일 타임에 오류가 발생해 런타임 버그를 예방합니다.
- 코드 가독성 향상: 해당 함수가 기반 클래스의 가상 함수를 재정의한다는 사실이 명확히 드러납니다.
- 유지보수 용이성: 기반 클래스의 가상 함수 시그니처가 변경될 경우, 이를 재정의하는 모든 파생 클래스에서 오류가 감지되므로 빠른 수정이 가능합니다.
마무리
C++11부터 도입된 override 키워드는 선택 사항이지만, 가상 함수를 재정의할 때 반드시 사용하는 것이 좋은 코딩 습관입니다. 작은 키워드 하나로 컴파일러의 검증 기능을 활용해 더 안전하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.