final 지정자

final 지정자 (final specifier)

가상 함수(virtual function)가 파생 클래스에서 더는 오버라이드될 수 없게 막거나, 클래스가 더는 상속될 수 없게 막는 final 지정자를 알아볼게요. 상속 설계에서 '여기까지'를 명시적으로 못 박고 싶을 때 쓰는 키워드입니다.

출처: cppreference

본문

문법

멤버 함수에 적용할 때 final 식별자는 클래스 정의 안의 멤버 함수 선언 또는 멤버 함수 정의 문법에서 declarator 바로 뒤에 나타나요.

클래스(구조체 struct와 공용체 union 포함)에 적용할 때 final 식별자는 클래스 정의의 맨 앞, 클래스 이름 바로 뒤에 나타나며, 클래스 선언(class declaration)에는 쓸 수 없어요.

    declarator virt-specifier-seq (optional) pure-specifier (optional) (1)
    declarator virt-specifier-seq (optional) function-body (2)
    class-key attr (optional) class-head-name class-virt-specifier (optional) base-clause (optional) (3)
  • (1) 멤버 함수 선언에서 final은 declarator 바로 뒤, pure-specifier(쓰는 경우) 앞의 virt-specifier-seq에 나타날 수 있어요.
  • (2) 클래스 정의 안의 멤버 함수 정의에서 final은 declarator 바로 뒤, function-body 바로 앞의 virt-specifier-seq에 나타날 수 있어요.
  • (3) 클래스 정의에서 final은 클래스 이름 바로 뒤, base-clause가 시작되는 콜론 바로 앞의 class-virt-specifier로 나타날 수 있어요.

(1), (2)의 경우 virt-specifier-seq는 쓰면 overridefinal, 또는 final overrideoverride final 중 하나예요. (3)의 경우 class-virt-specifier의 허용 값은 쓰면 final뿐입니다.

설명

가상 함수 선언이나 정의에 final을 쓰면, 이 함수가 가상임을 보장하고 파생 클래스에서 오버라이드될 수 없음을 지정해요. 그렇지 않으면 프로그램은 ill-formed이 되며(즉 컴파일 타임 오류가 생성되고) 컴파일되지 않아요.

클래스 정의에 final을 쓰면 이 클래스가 다른 클래스 정의의 base-specifier-list에 나타날 수 없다는 것, 다시 말해 상속될 수 없다는 것을 지정해요. 그렇지 않으면 ill-formed이 됩니다. (컴파일 타임 오류가 생성돼요.) final은 공용체 정의에도 쓸 수 있는데, 공용체는 어차피 상속될 수 없으므로 아무 효과가 없어요(std::is_final의 결과에 영향을 주는 것 외에는, C++14부터).

final은 멤버 함수 선언이나 클래스 헤드(class head)에 쓰일 때 특별한 의미를 갖는 식별자예요. 다른 맥락에서는 예약어가 아니며, 객체나 함수의 이름으로 쓸 수 있습니다.

참고 사항

다음 토큰들의 연속에서:

  • class, struct, union 중 하나
  • 한정될 수 있는 식별자(possibly qualified identifier)
  • final
  • :{ 중 하나

세 번째 토큰 final은 항상 식별자가 아닌 지정자(specifier)로 간주돼요.

struct A;
struct A final {}; // OK, definition of struct A,
                   // not value-initialization of variable final

struct X
{
    struct C { constexpr operator int() { return 5; } };
    struct B final : C{}; // OK, definition of nested class B,
                          // not declaration of a bit-field member final
};

// Abnormal final usage.

struct final final // OK, definition of a struct named “final” from which
{                  // you cannot inherit
};

// struct final final {}; // Error: redefinition of “struct final”, NOT a
                          // definition of a variable “final” using an elaborated
                          // type specifier “struct final” followed by an
                          // aggregate initialization

// struct override : final {}; // Error: cannot derive from final base type;
                               // “override” in given context is a normal name
void foo()
{
    [[maybe_unused]]
    final final; // OK, declaration of a variable named “final” of type
                 // “struct final”
}

struct final final; // OK, declaration of a variable named “final” of type
                    // “struct final” using an elaborated type specifier
int main()
{
}

키워드

final

예제

final이 가상 함수와 파생에 각각 어떻게 적용되는지, 어떤 자리에서 오류가 나는지 확인해 볼게요.

struct Base
{
    virtual void foo();
};

struct A : Base
{
    void foo() final; // Base::foo is overridden and A::foo is the final override
    void bar() final; // Error: bar cannot be final as it is non-virtual
};

struct B final : A // struct B is final
{
    void foo() override; // Error: foo cannot be overridden as it is final in A
};

struct C : B {}; // Error: B is final

가능한 출력:

main.cpp:9:10: error: 'void A::bar()' marked 'final', but is not virtual
    9 |     void bar() final; // Error: bar cannot be final as it is non-virtual
      |          ^~~
main.cpp:14:10: error: virtual function 'virtual void B::foo()' overriding final function
   14 |     void foo() override; // Error: foo cannot be overridden as it is final in A
      |          ^~~
main.cpp:8:10: note: overridden function is 'virtual void A::foo()'
    8 |     void foo() final; // Base::foo is overridden and A::foo is the final override
      |          ^~~
main.cpp:17:8: error: cannot derive from 'final' base 'B' in derived type 'C'
   17 | struct C : B // Error: B is final
      |

더 알아보기 (Learn more)