Namespaces
Variants

Non-static member functions

From ko.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
Special member functions
Templates
Miscellaneous

비정적 멤버 함수는 클래스의 멤버 명세 에서 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 의 비정적 멤버 함수는 호출될 수 있습니다

1) 클래스 멤버 접근 연산자를 사용하여 X 타입의 객체에 대해
2) X 에서 파생된 클래스의 객체에 대해
3) X 의 멤버 함수 본문 내에서 직접
4) 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(매개변수 목록 뒤의 & 토큰) 또는 rvalue ref-qualifier(매개변수 목록 뒤의 && 토큰)와 함께 선언될 수 있습니다. 오버로드 해결 동안 클래스 X의 cv-qualifier 시퀀스를 가진 암시적 객체 멤버 함수는 다음과 같이 처리됩니다:

  • ref-qualifier 없음: 암시적 객체 매개변수는 cv-qualified X에 대한 lvalue 참조 타입을 가지며 추가적으로 rvalue 암시적 객체 인자에 바인딩하는 것이 허용됨
  • lvalue ref-qualifier: 암시적 객체 매개변수는 cv-qualified X에 대한 lvalue 참조 타입을 가짐
  • rvalue ref-qualifier: 암시적 객체 매개변수는 cv-qualified X에 대한 rvalue 참조 타입을 가짐
#include <iostream>
struct S
{
    void f() &  { std::cout << "lvalue\n"; }
    void f() && { std::cout << "rvalue\n"; }
};
int main()
{
    S s;
    s.f();            // prints "lvalue"
    std::move(s).f(); // prints "rvalue"
    S().f();          // prints "rvalue"
}

참고: cv-qualification과 달리, ref-qualification은 this 포인터의 속성을 변경하지 않습니다: rvalue ref-qualified 함수 내에서 * this 는 lvalue 표현식으로 남아 있습니다.

(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 비정적 멤버 함수가 자신이 속한 클래스 이름과
동일한 이름을 가질 수 있는지 여부가 모호함
명시적 이름 제한 추가됨

참고 항목