본문 바로가기
프로그래밍/C || CPP

C++ virtual, override, final 키워드별 사용하는 이유를 알아보자.

by _BlankSpace 2019. 6. 18.

C++을 입문하시면서, 상속에 관해서 공부를 하셨을 거에요. 이때, 나오는 키워드가 virtual 입니다.

 

때문에, virtual 이라는 키워드는 꽤나 눈에 익으셨을텐데요. 혹시, override와 final도 오버라이딩에서 사용하는 키워드라는 것을 아시나요?

 

사실, override와 final은 C++11 이후에 등장합니다. 때문에, 못 보셨을 수도 있습니다. 하지만, 새롭게 추가된만큼 어딘가에 사용하면 유용하다는 뜻이겠죠?

 

이번 포스팅에서는 virtual, override, final 키워드가 각각 어떠한 경우에 사용하는 지에 대해서 정리하도록 하겠습니다.

 

일단, 각 키워드가 무엇을 뜻하는 지 알아보자.

위에서 말한 것처럼, virtual, override, final은 모두 상속 관련 오버라이딩을 할 때 사용한다고 하였습니다. 그런데, 조금씩 사용 용도가 다르다는 것인데..

 

일단, 각 키워드가 무엇을 뜻하는 지 알아보는 것이 좋을 것 같습니다. 이 포스팅에서는 각 키워드에 대해서 너무 자세하게는 설명하지 않도록 하겠습니다.

 

먼저, virtual 키워드는 흔히 가상 함수를 뜻합니다. 가상함수에는 함수의 몸체를 정의하지 않는 순수 가상함수와 정의를 하는 일반 가상함수로 나눌 수 있습니다.

보통, virtual 키워드를 붙이면, 해당 클래스를 상속받는 하위 클래스에서 virtual 키워드의 함수를 재정의(오버라이딩) 한다는 뜻입니다.

그리고 virtual 키워드는 보통 가상 함수의 처음 부분에 붙입니다. 즉, 부모 클래스에 붙인다고 생각하시면 되겠습니다.

 

다음으로 override은 위에서 말한 것처럼 c++11 이후로 나온 키워드 입니다. 이 키워드도 가상함수를 가르키기 위한 키워드라고 할 수 있습니다.

다만, override와 virtual이 다른 점은 키워드를 붙이는 위치라고 할 수 있습니다. 위에서 말한 것처럼, virtual은 가상함수의 시작 부분에 붙인다면, override는 하위 클래스의 가상함수에 붙입니다. 즉, 이 가상함수가 상속받아서 오버라이딩한 함수다라는 것을 뜻하는 것입니다.

 

마지막으로 final 키워드도 c++11 이후로 나왔습니다. 이 키워드도 마찬가지로 가상함수를 가르킵니다.

final은 가상함수의 마지막을 가르키는 키워드라고 생각하시면 되겠습니다. 즉, 계속해서 오버라이딩을 진행하다가 마지막 하위 클래스에서의 가상함수에는 virtual, override가 아닌 final을 붙인다는 것이죠.

이것은 더 이상 가상함수를 오버라이딩하지 않겠다는 뜻도 됩니다.

 

글로만 표현하다보니, 제대로 이해가 되지 않으실 수 있을거에요. 그래서 바로 예제로 설명하도록 하겠습니다.

 

 

그럼, 각 키워드를 예제로 이해해보자.

아주 간단하게 세 가지 키워드로 예제를 만들어보았습니다.

 

struct BaseTest
{
    virtual void test(); // 가상함수의 첫 시작은 virtual 키워드.
};

struct SubATest : public BaseTest
{
    void test() override; // 상속받은 가상함수에는 override 키워드.
};

struct SubBTest : public SubATest
{
    void test() final; // 가상함수의 마지막에는 final 키워드.
};

 

위에 코드를 설명하겠습니다.

먼저, BaseTest 구조체에서 test() 가상함수를 만들었습니다. 이때, 가상함수를 하위에서 오버라이딩할 것이므로, virtual이라는 키워드를 붙였습니다.

 

이후, SubATest 구조체에서 BaseTest 구조체를 상속받습니다. 이후, test() 가상함수는 또 오버라이딩할 것이므로, override 키워드를 붙입니다. 주의할 점은, virtual 키워드를 붙여도 차이점은 없다는 것입니다.

다만, override를 붙여주면 이 가상함수가 처음 선언될 경우에 에러를 발생시킵니다. 이 점으로 인해서, 개발할 때에 도움을 얻을 수 있겠죠.

만약, virtual 키워드만 사용한다면 어떻게 될까요? 아래 예제를 보면서 설명하도록 할께요.

1번과 2번 가상함수를 오버라이딩을 목적으로 만들었다고 예로 들어볼께요. 이것은 같은 가상함수라고 판단할까요?

당연히, 다른 가상함수로 판단합니다. 그 이유는 인자가 달라졌으니깐요.

1. virtual void test(int a);

2. virtual void test(char a);

그러므로, 이러한 경우를 예방하기 위해서 override 키워드를 사용합니다. 그러면, 빌드 시에 에러가 발생하기 때문에 잘못되었다는 것을 사전에 알 수 있습니다.

아래는 빌드 시에 발생하는 에러 메시지 입니다. 이처럼, 바로 확인할 수 있겠죠?

FinalExample.cpp:10:10: error: ‘void SubATest::test(char)’ marked ‘override’, but does not override
     void test(char b) override;

 

 

마지막으로 SubBTest 구조체에서는 SubATest 구조체를 상속받습니다. 이후에 test() 가상함수는 더 이상 오버라이딩을 하지 않을 것이므로, final 키워드를 붙입니다. 이때도 마찬가지로 vitual 또는 override 키워드를 붙여도 상관 없습니다.

다만, SubBTest를 상속받는 하위 구조체에서 test()를 더이상 오버라이딩할 수 없게 만들어 주는 키워드라고 생각하시면 되겠습니다.

만약, final 키워드가 붙은 가상함수를 오버라이딩하려고 한다면 빌드 에러가 발생하므로, 사전에 잘못된 부분을 고칠 수 있습니다.

아래 예를 봐주세요. SubATest의 test() 에서 final 키워드를 붙였습니다. 하지만, SubBTest에서 test()를 재정의하려 합니다. 문제가 발생할까요?

struct BaseTest
{
    virtual void test();
};

struct SubATest : public BaseTest
{
    void test() final;
};

struct SubBTest : public SubATest
{
    void test() final;
};

 

당연히, 문제가 발생합니다. 아래 메시지 처럼 final 키워드를 사용했으면, 하위 클래스 또는 구조체에서 오버라이딩을 할 수 없습니다.

FinalExample.cpp:15:10: error: virtual function ‘virtual void SubBTest::test()’
     void test() override;
          ^
FinalExample.cpp:10:10: error: overriding final function ‘virtual void SubATest::test()’
     void test() final;
          ^

 

이상으로, virtual, override 그리고 final에 대한 정리를 마치겠습니다. 혹시, 이해가 안되시거나 잘못된 내용이 있다면 댓글 부탁드립니다!

댓글