Namespaces
Variants

final specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Virtual function
override specifier (C++11)
final specifier (C++11)
Special member functions
Templates
Miscellaneous

가상 함수가 파생 클래스에서 virtual function 재정의될 수 없음을 지정하거나, 클래스가 derived from 파생될 수 없음을 지정합니다.

목차

구문

멤버 함수에 적용될 때, 식별자 final 은 클래스 정의 내부의 멤버 함수 선언 또는 멤버 함수 정의 구문에서 선언자 바로 뒤에 나타납니다.

클래스(구조체(struct)와 공용체(union) 포함)에 적용될 때, 식별자 final 는 클래스 정의의 시작 부분, 클래스 이름 바로 뒤에 나타나며, 클래스 선언에서는 나타날 수 없습니다.

declarator virt-specifier-seq  (선택적) pure-specifier  (선택적) (1)
declarator virt-specifier-seq  (선택적) function-body (2)
class-key attr  (선택적) class-head-name class-virt-specifier  (선택적) base-clause  (선택적) (3) (C++26 이전)
class-key attr  (선택적) class-head-name class-prop-specifier-seq  (선택적) base-clause  (선택적) (4) (C++26 이후)
1) 멤버 함수 선언에서, final 는 선언자 바로 뒤, virt-specifier-seq 내에 위치할 수 있으며, 사용되는 경우 pure-specifier 앞에 올 수 있습니다.
2) 클래스 정의 내부의 멤버 함수 정의에서, final virt-specifier-seq 에서 선언자 바로 뒤와 function-body 바로 앞에 나타날 수 있습니다.
3) 클래스 정의에서, final 는 클래스 이름 바로 뒤, 사용된 경우 base-clause 를 시작하는 콜론 바로 앞에서 class-virt-specifier 로 나타날 수 있습니다.
4) 클래스 정의에서, final class-prop-specifier-seq 에 나타날 수 있으며, 사용되는 경우 단 한 번만 사용할 수 있습니다.

경우 (1,2) 에서, virt-specifier-seq 가 사용된다면, 이는 override 또는 final , 또는 final override 또는 override final 입니다. 경우 (3) 에서, class-virt-specifier 가 사용된다면 허용되는 유일한 값은 final 입니다. 경우 (4) 에서, class-prop-specifier-seq 가 사용된다면, 임의의 개수의 class property specifiers (C++26부터) 를 가질 수 있지만, 각각은 최대 한 번만 나타날 수 있습니다.

설명

가상 함수 선언이나 정의에서 사용될 때, final 지정자는 함수가 가상 함수임을 보장하며 파생 클래스에서 재정의될 수 없도록 지정합니다. 그렇지 않으면 프로그램이 올바르지 않습니다(컴파일 타임 오류가 발생함).

클래스 정의에서 사용될 때, final 는 이 클래스가 다른 클래스 정의의 base-specifier-list 에 나타날 수 없음을 지정합니다(다시 말해, 상속될 수 없음). 그렇지 않으면 프로그램이 ill-formed입니다(컴파일 타임 오류가 발생함). final union 정의와 함께 사용될 수도 있으며, 이 경우 (다른 결과에 영향을 미치는 std::is_final 의 결과를 제외하고) (C++14부터) 효과가 없습니다. 왜냐하면 union은 상속될 수 없기 때문입니다.

final 는 멤버 함수 선언이나 클래스 헤드에서 사용될 때 특별한 의미를 갖는 식별자입니다. 다른 상황에서는 예약어가 아니며 객체와 함수의 이름을 지정하는 데 사용될 수 있습니다.

참고

다음 토큰들의 시퀀스에서:

  1. 다음 중 하나 class , struct union
  2. 가능한 한정된 식별자
  3. final
  4. 다음 중 하나 : {

시퀀스의 세 번째 토큰 final 은 항상 식별자가 아닌 지정자로 간주됩니다.

struct A;
struct A final {}; // OK, 구조체 A의 정의,
                   // final 변수의 값 초기화가 아님
struct X
{
    struct C { constexpr operator int() { return 5; } };
    struct B final : C{}; // OK, 중첩 클래스 B의 정의,
                          // 비트 필드 멤버 final의 선언이 아님
};
// 비정상적인 final 사용
struct final final // OK, 상속할 수 없는 `final`이라는 이름의 구조체 정의
{                  // (final 키워드로 선언된 구조체)
};
// struct final final {}; // 오류: `struct final`의 재정의,
                          // 정교화된 타입 지정자 `struct final` 다음에
                          // 집합 초기화가 오는 변수 `final`의 정의가 아님
// struct override : final {}; // 오류: final 기본 타입으로부터 상속할 수 없음;
                               // 주어진 문맥에서 `override`는 일반 이름임
void foo()
{
    [[maybe_unused]]
    final final; // OK, `struct final` 타입의 `final`이라는 변수 선언
                 // 
}
struct final final; // OK, 정교화된 타입 지정자를 사용한
                    // `struct final` 타입의 `final`이라는 변수 선언
int main()
{
}

키워드

final

예제

struct Base
{
    virtual void foo();
};
struct A : Base
{
    void foo() final; // Base::foo가 재정의되고 A::foo가 최종 재정의입니다
    void bar() final; // 오류: bar는 비가상 함수이므로 final로 지정할 수 없음
};
struct B final : A // struct B는 final입니다
{
    void foo() override; // 오류: foo는 A에서 final로 지정되어 재정의할 수 없음
};
struct C : B {}; // 오류: B는 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
      |

참고문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 11 클래스 [class]
  • 11.7.3 가상 함수 [class.virtual]
  • C++20 표준(ISO/IEC 14882:2020):
  • 11 클래스 [class]
  • 11.7.2 가상 함수 [class.virtual]
  • C++17 표준(ISO/IEC 14882:2017):
  • 12 클래스 [class]
  • 13.3 가상 함수 [class.virtual]
  • C++14 표준(ISO/IEC 14882:2014):
  • 9 클래스 [class]
  • 10.3 가상 함수 [class.virtual]
  • C++11 표준 (ISO/IEC 14882:2011):
  • 9 클래스 [class]
  • 10.3 가상 함수 [class.virtual]

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 1318 C++11 클래스 이름 뒤에 final 이 있고 빈 멤버 명세 목록을 가진
클래스 정의가 final 을 식별자로 만들 수 있음
final 는 이 경우 항상
지정자(specifier)임

참고 항목

override 지정자 (C++11) 메서드가 다른 메서드를 재정의함을 명시적으로 선언
클래스 속성 지정자 (C++26) final 지정자 (C++11) , 대체 가능성 (C++26) , 단순 재배치 가능성 (C++26)