Namespaces
Variants

Non-static member functions

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

참고 항목