Non-static member functions
비정적 멤버 함수는 클래스의
멤버 명세
에서
static
또는
friend
지정자 없이 선언된 함수입니다
(이 키워드들의 효과에 대해서는
정적 멤버 함수
와
friend 선언
을 참조하십시오).
class S { int mf1(); // 비정적 멤버 함수 선언 void mf2() volatile, mf3() &&; // cv 한정자와/또는 참조 한정자를 가질 수 있음 // 위 선언은 두 개의 개별 선언과 동등함: // void mf2() volatile; // void mf3() &&; int mf4() const { return data; } // 인라인으로 정의 가능 virtual void mf5() final; // 가상 함수일 수 있으며, final/override 사용 가능 S() : data(12) {} // 생성자도 멤버 함수임 int data; }; int S::mf1() { return 7; } // 인라인으로 정의되지 않으면 네임스페이스에서 정의해야 함
생성자 , 소멸자 , 그리고 변환 함수 는 선언에 특별한 구문을 사용합니다. 이 페이지에서 설명하는 규칙들은 이러한 함수들에는 적용되지 않을 수 있습니다. 자세한 내용은 각각의 페이지를 참조하십시오.
|
명시적 객체 멤버 함수 는 명시적 객체 매개변수 를 갖는 비정적 멤버 함수입니다. |
(since C++23) |
암시적 객체 멤버 함수 는 명시적 객체 매개변수가 없는 비정적 멤버 함수입니다(C++23 이전에는 이것이 비정적 멤버 함수의 유일한 종류였으며, 따라서 문헌에서 "비정적 멤버 함수"라고 지칭되었습니다).
목차 |
설명
모든
함수 선언
이 허용되며, 비정적 멤버 함수에서만 사용 가능한 추가 구문 요소들이 있습니다:
pure-specifiers
, cv-qualifiers
, ref-qualifiers,
final
및
override
지정자
(C++11부터)
, 그리고
멤버 초기화 리스트
.
클래스
X
의 비정적 멤버 함수는 호출될 수 있습니다
X
타입의 객체에 대해
X
의 멤버 함수 본문 내에서 직접
X
로부터 파생된 클래스의 멤버 함수 본문 내에서 직접
X
클래스의 비정적 멤버 함수를
X
타입이 아니거나
X
에서 파생된 타입이 아닌 객체에 대해 호출하는 경우
정의되지 않은 동작을 유발합니다.
비정적 멤버 함수 본문 내에서,
X
의 비타입 비정적 멤버 또는
X
의 기본 클래스의 비타입 비정적 멤버로 해석되는 모든
id-expression
e
(예: 식별자)는 멤버 접근 표현식
(
*
this
)
.
e
으로 변환됩니다(이미 멤버 접근 표현식의 일부인 경우 제외). 이 변환은 템플릿 정의 컨텍스트에서는 발생하지 않으므로,
의존 이름
이 되기 위해 명시적으로
this
-
>
를 접두사로 추가해야 할 수 있습니다.
struct S { int n; void f(); }; void S::f() { n = 1; // (*this).n = 1;로 변환됨 } int main() { S s1, s2; s1.f(); // s1.n을 변경함 }
비정적 멤버 함수 본문 내에서,
X
의 정적 멤버, 열거자 또는 중첩 타입으로 해석되는 모든 비한정 식별자는
X
또는
X
의 기본 클래스에 대해 해당하는 한정 식별자로 변환됩니다:
struct S { static int n; void f(); }; void S::f() { n = 1; // S::n = 1;로 변환됨 } int main() { S s1, s2; s1.f(); // S::n을 변경함 }
cv 한정자를 갖는 멤버 함수
암시적 객체 멤버 함수는 cv-qualifier 시퀀스( const , volatile , 또는 const 와 volatile 의 조합)로 선언될 수 있으며, 이 시퀀스는 함수 선언 에서 매개변수 목록 뒤에 나타납니다. 서로 다른 cv-qualifier 시퀀스(또는 시퀀스 없음)를 가진 함수들은 서로 다른 타입을 가지므로 서로 오버로드될 수 있습니다.
cv 한정자 시퀀스를 가진 함수 본문 내에서,
*
this
는 cv 한정됩니다. 예를 들어,
const
한정자를 가진 멤버 함수 내에서는 일반적으로
const
한정자를 가진 다른 멤버 함수만 호출할 수 있습니다.
const
한정자가 없는 멤버 함수는
const_cast
가 적용되거나
this
를 포함하지 않는 접근 경로를 통해 호출될 수 있습니다.
#include <vector> struct Array { std::vector<int> data; Array(int sz) : data(sz) {} // const 멤버 함수 int operator[](int idx) const { // this 포인터의 타입은 const Array* return data[idx]; // (*this).data[idx];로 변환됨 } // non-const 멤버 함수 int& operator[](int idx) { // this 포인터의 타입은 Array* return data[idx]; // (*this).data[idx]로 변환됨 } }; int main() { Array a(10); a[1] = 1; // OK: a[1]의 타입은 int& const Array ca(10); ca[1] = 2; // Error: ca[1]의 타입은 int }
ref-qualifier가 있는 멤버 함수
암시적 객체 멤버 함수는 ref-qualifier 없이, lvalue ref-qualifier(매개변수 목록 뒤의
참고: cv-qualification과 달리, ref-qualification은
|
(C++11부터) |
가상 및 순수 가상 함수
비정적 멤버 함수는 virtual 또는 pure virtual 로 선언될 수 있습니다. 자세한 내용은 virtual functions 와 abstract classes 를 참조하십시오.
명시적 객체 멤버 함수cv-qualifier나 ref-qualifier 없이 선언된 비정적 비가상 멤버 함수의 경우, 첫 번째 매개변수가 함수 매개변수 팩 이 아니라면 명시적 객체 매개변수 (접두사 키워드 this 로 표기)가 될 수 있습니다: struct X { void foo(this X const& self, int i); // same as void foo(int i) const &; // void foo(int i) const &; // Error: already declared void bar(this X self, int i); // pass object by value: makes a copy of “*this” }; 멤버 함수 템플릿의 경우, 명시적 객체 매개변수를 통해 타입과 값 범주 추론이 가능하며, 이 언어 기능은 "deducing this "라고 불립니다: struct X { template<typename Self> void foo(this Self&&, int); }; struct D : X {}; void ex(X& x, D& d) { x.foo(1); // Self = X& move(x).foo(2); // Self = X d.foo(3); // Self = D& } 이를 통해 const 및 비 const 멤버 함수의 중복을 제거할 수 있습니다. 예시는 배열 첨자 연산자 를 참조하십시오. 명시적 객체 멤버 함수 본문 내에서는 this 포인터를 사용할 수 없습니다: 모든 멤버 접근은 정적 멤버 함수에서와 같이 첫 번째 매개변수를 통해 이루어져야 합니다: struct C { void bar(); void foo(this C c) { auto x = this; // error: no this bar(); // error: no implicit this-> c.bar(); // ok } }; 명시적 객체 멤버 함수에 대한 포인터는 멤버에 대한 포인터가 아닌 일반 함수 포인터입니다: struct Y { int f(int, int) const&; int g(this Y const&, int, int); }; auto pf = &Y::f; pf(y, 1, 2); // error: pointers to member functions are not callable (y.*pf)(1, 2); // ok std::invoke(pf, y, 1, 2); // ok auto pg = &Y::g; pg(y, 3, 4); // ok (y.*pg)(3, 4); // error: “pg” is not a pointer to member function std::invoke(pg, y, 3, 4); // ok |
(C++23부터) |
특수 멤버 함수
일부 멤버 함수는 특수(special) 합니다: 특정 상황에서 사용자가 정의하지 않아도 컴파일러에 의해 정의됩니다. 이들은 다음과 같습니다:
| (C++11부터) |
| (C++11부터) |
특수 멤버 함수 와 비교 연산자 (C++20부터) 는 기본 설정(defaulted) 될 수 있는 유일한 함수들입니다. 즉, 함수 본체 대신 = default 를 사용하여 정의할 수 있습니다(자세한 내용은 해당 페이지 참조).
참고 사항
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_ref_qualifiers
|
200710L
|
(C++11) | 참조 한정자 |
__cpp_explicit_this_parameter
|
202110L
|
(C++23) |
명시적 객체 매개변수
(
this
추론
)
|
예제
#include <exception> #include <iostream> #include <string> #include <utility> struct S { int data; // 단순 변환 생성자 (선언) S(int val); // 단순 explicit 생성자 (선언) explicit S(std::string str); // const 멤버 함수 (정의) virtual int getData() const { return data; } }; // 생성자 정의 S::S(int val) : data(val) { std::cout << "ctor1 called, data = " << data << '\n'; } // 이 생성자는 catch 절을 가짐 S::S(std::string str) try : data(std::stoi(str)) { std::cout << "ctor2 called, data = " << data << '\n'; } catch(const std::exception&) { std::cout << "ctor2 failed, string was '" << str << "'\n"; throw; // 생성자의 catch 절은 항상 재던져야 함 } struct D : S { int data2; // 기본 인자를 가진 생성자 D(int v1, int v2 = 11) : S(v1), data2(v2) {} // 가상 멤버 함수 int getData() const override { return data * data2; } // lvalue 전용 할당 연산자 D& operator=(D other) & { std::swap(other.data, data); std::swap(other.data2, data2); return *this; } }; int main() { D d1 = 1; S s2("2"); try { S s3("not a number"); } catch(const std::exception&) {} std::cout << s2.getData() << '\n'; D d2(3, 4); d2 = d1; // OK: lvalue에 대한 할당 // D(5) = d1; // ERROR: 적합한 operator= 오버로드 없음 }
출력:
ctor1 called, data = 1 ctor2 called, data = 2 ctor2 failed, string was 'not a number' 2 ctor1 called, data = 3
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 194 | C++98 |
비정적 멤버 함수가 자신이 속한 클래스 이름과
동일한 이름을 가질 수 있는지 여부가 모호함 |
명시적 이름 제한 추가됨 |