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 指定子なしで宣言される関数です (これらのキーワードの効果については、 静的メンバ関数 および フレンド宣言 を参照してください)。

class S
{
    int mf1(); // 非静的メンバ関数の宣言
    void mf2() volatile, mf3() &&; // cv修飾子や参照修飾子を持つことができる
        // 上記の宣言は2つの独立した宣言と等価:
        // void mf2() volatile;
        // void mf3() &&;
    int mf4() const { return data; } // インラインで定義可能
    virtual void mf5() final; // virtualにでき、final/overrideを使用可能
    S() : data(12) {} // コンストラクタもメンバ関数
    int data;
};
int S::mf1() { return 7; } // インラインで定義されない場合、名前空間で定義する必要がある

Constructors destructors 、および conversion functions は、宣言に特別な構文を使用します。このページで説明されているルールはこれらの関数には適用されない場合があります。詳細についてはそれぞれのページを参照してください。

明示的オブジェクトメンバ関数 は、 明示的オブジェクトパラメータ を持つ非静的メンバ関数である。

(C++23以降)

暗黙のオブジェクトメンバ関数は、明示的なオブジェクトパラメータを持たない非静的メンバ関数です(C++23以前では、これは非静的メンバ関数の唯一の種類であり、文献では「非静的メンバ関数」と呼ばれていました)。

目次

翻訳の注意点: - HTMLタグ、属性、
タグ内のテキストは翻訳していません
- C++専門用語(cv-qualifiers、ref-qualifier、virtual functionsなど)は原文のまま保持しています
- 「Contents」のみ「目次」に翻訳しました
- その他のテキストはC++の文脈を考慮して適切に翻訳しています
- 元の書式と構造を完全に保持しています

説明

任意の 関数宣言 が許可されており、非静的メンバー関数でのみ使用可能な追加の構文要素があります: pure-specifiers 、cv-qualifiers 、ref-qualifiers、 final および override 指定子 (C++11以降) 、そして メンバー初期化リスト

X クラスの非静的メンバ関数は呼び出し可能です

1) X のオブジェクトに対してクラスメンバアクセス演算子を使用する場合
2) クラス derived のオブジェクトについて、 X から
3) X のメンバー関数本体から直接
4) クラス X から派生したクラスのメンバー関数本体から直接

X クラスの非静的メンバー関数を、 X 型、または X から派生した型ではないオブジェクトに対して呼び出すと、未定義動作を引き起こします。

X の非静的メンバ関数の本体内部では、 X または X の基底クラスの非型非静的メンバに解決される任意の id-expression e (例えば識別子)は、メンバアクセス式 ( * this ) . e に変換されます(既にメンバアクセス式の一部である場合を除く)。これはテンプレート定義コンテキストでは発生しないため、名前を dependent にするには明示的に 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修飾子 シーケンス( const volatile 、または const volatile の組み合わせ)で宣言できます。このシーケンスは 関数宣言 のパラメータリストの後に記述されます。異なるCV修飾子シーケンス(またはシーケンスなし)を持つ関数は異なる型を持つため、互いにオーバーロードすることができます。

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] に変換される
    }
    // 非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; // エラー: ca[1] の型は int
}

参照修飾子付きメンバ関数

暗黙のオブジェクトメンバ関数は、参照修飾子なし、左辺値参照修飾子(パラメータリスト後のトークン & )、または右辺値参照修飾子(パラメータリスト後のトークン && )を付けて宣言できます。 オーバーロード解決 において、クラスXのcv修飾子シーケンスを持つ暗黙のオブジェクトメンバ関数は以下のように扱われます:

  • 参照修飾子なし:暗黙のオブジェクトパラメータはcv修飾されたXへの左辺値参照型を持ち、さらに右辺値の暗黙オブジェクト引数へのバインドが許可されます
  • 左辺値参照修飾子:暗黙のオブジェクトパラメータはcv修飾されたXへの左辺値参照型を持ちます
  • 右辺値参照修飾子:暗黙のオブジェクトパラメータはcv修飾されたXへの右辺値参照型を持ちます
#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修飾とは異なり、参照修飾は this ポインタのプロパティを変更しません:右辺値参照修飾子付き関数内では、 * this は左辺値式のままです。

(C++11以降)

仮想関数と純粋仮想関数

非静的メンバ関数は virtual または pure virtual として宣言できます。詳細については virtual functions および abstract classes を参照してください。

明示的オブジェクトメンバ関数

cv修飾子または参照修飾子で宣言されていない非静的非仮想メンバ関数について、その最初のパラメータが 関数パラメータパック でない場合、 明示的オブジェクトパラメータ (接頭辞キーワード 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”
};

メンバ関数テンプレートの場合、明示的オブジェクトパラメータは型と値カテゴリの推論を可能にし、この言語機能は「 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以降)
(since C++11)
HTMLタグ、属性、C++固有の用語は翻訳せず、元のフォーマットを保持します。

特殊メンバ関数 および 比較演算子 (C++20以降) は、 デフォルト化 可能な唯一の関数です。つまり、関数本体の代わりに = default を使用して定義することができます(詳細は各ページを参照してください)。

注記

機能テストマクロ 規格 機能
__cpp_ref_qualifiers 200710L (C++11) ref-qualifiers
__cpp_explicit_this_parameter 202110L (C++23) explicit object parameter ( deducing this )

#include <exception>
#include <iostream>
#include <string>
#include <utility>
struct S
{
    int data;
    // 単純な変換コンストラクタ(宣言)
    S(int val);
    // 単純な明示的コンストラクタ(宣言)
    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; }
    // 左辺値専用代入演算子
    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: 左辺値への代入
//  D(5) = d1; // エラー: 適切な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 非静的メンバー関数が外側のクラス名と同じ名前を持つことができるかどうかが曖昧 明示的な命名制限が追加された

関連項目