final
specifier
(since C++11)
가상 함수가 파생 클래스에서 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 이후) | |||||||
final
는 선언자 바로 뒤,
virt-specifier-seq
내에 위치할 수 있으며, 사용되는 경우
pure-specifier
앞에 올 수 있습니다.
final
는
virt-specifier-seq
에서 선언자 바로 뒤와
function-body
바로 앞에 나타날 수 있습니다.
final
는 클래스 이름 바로 뒤, 사용된 경우
base-clause
를 시작하는 콜론 바로 앞에서
class-virt-specifier
로 나타날 수 있습니다.
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 는 멤버 함수 선언이나 클래스 헤드에서 사용될 때 특별한 의미를 갖는 식별자입니다. 다른 상황에서는 예약어가 아니며 객체와 함수의 이름을 지정하는 데 사용될 수 있습니다.
참고
다음 토큰들의 시퀀스에서:
- 다음 중 하나 class , struct 및 union
- 가능한 한정된 식별자
- final
- 다음 중 하나 : 및 {
시퀀스의 세 번째 토큰 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() { }
키워드
예제
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) |