名前空間
変種
操作

非静的メンバ関数

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

非静的メンバ関数は、クラスのメンバ仕様で、staticまたはfriend指定子なしで宣言された関数です (静的メンバ関数およびフレンド宣言でこれらのキーワードの効果を参照)。

class S
{
    int mf1(); // non-static member function declaration
    void mf2() volatile, mf3() &&; // can have cv-qualifiers and/or a reference-qualifier
        // the declaration above is equivalent to two separate declarations:
        // void mf2() volatile;
        // void mf3() &&;
 
    int mf4() const { return data; } // can be defined inline
    virtual void mf5() final; // can be virtual, can use final/override
    S() : data(12) {} // constructors are member functions too
    int data;
};
 
int S::mf1() { return 7; } // if not defined inline, has to be defined at namespace

コンストラクタデストラクタ、および変換関数は、その宣言に特殊な構文を使用します。このページで説明されている規則は、これらの関数には適用されない場合があります。詳細については、それぞれのページを参照してください。

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

(C++23から)

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

目次

[編集] 説明

あらゆる関数宣言が許可され、非静的メンバ関数にのみ利用可能な追加の構文要素があります: 純粋指定子、cv修飾子、ref修飾子、finalおよびoverride指定子(C++11以降)、およびメンバ初期化リスト

クラスXの非静的メンバ関数は、次のように呼び出すことができます。

1) クラスメンバアクセス演算子を使用して型Xのオブジェクトに対して
2) Xから派生したクラスのオブジェクトに対して
3) Xのメンバ関数の本体内から直接
4) Xから派生したクラスのメンバ関数の本体内から直接

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

Xの非静的メンバ関数の本体内で、Xの非型非静的メンバまたはXの基底クラスの非型非静的メンバに解決されるid-expression e (例: 識別子) は、メンバアクセス式 (*this).e に変換されます (すでにメンバアクセス式の一部である場合を除く)。これはテンプレート定義コンテキストでは発生しないため、依存させるために明示的にthis->をプレフィックスとして付ける必要がある場合があります。

struct S
{
    int n;
    void f();
};
 
void S::f()
{
    n = 1; // transformed to (*this).n = 1;
}
 
int main()
{
    S s1, s2;
    s1.f(); // changes s1.n
}

Xの非静的メンバ関数の本体内で、XまたはXの基底クラスの静的メンバ、列挙子、または入れ子型に解決される修飾なしIDは、対応する修飾IDに変換されます。

struct S
{
    static int n;
    void f();
};
 
void S::f()
{
    n = 1; // transformed to S::n = 1;
}
 
int main()
{
    S s1, s2;
    s1.f(); // changes S::n
}

[編集] cv修飾子付きメンバ関数

暗黙的オブジェクトメンバ関数は、cv修飾子シーケンス (constvolatile、またはconstvolatileの組み合わせ) を付けて宣言できます。このシーケンスは、関数宣言のパラメータリストの後に記述されます。異なるcv修飾子シーケンス (またはシーケンスなし) を持つ関数は異なる型を持ち、互いにオーバーロードできます。

cv修飾子シーケンスを持つ関数の本体では、*thisはcv修飾されます。たとえば、const修飾子を持つメンバ関数では、const修飾子を持つ他のメンバ関数のみが通常どおり呼び出されます。const修飾子を持たないメンバ関数は、const_castが適用される場合、またはthisを含まないアクセスパスを介して呼び出すことができます。

#include <vector>
 
struct Array
{
    std::vector<int> data;
    Array(int sz) : data(sz) {}
 
    // const member function
    int operator[](int idx) const
    {                     // the this pointer has type const Array*
        return data[idx]; // transformed to (*this).data[idx];
    }
 
    // non-const member function
    int& operator[](int idx)
    {                     // the this pointer has type Array*
        return data[idx]; // transformed to (*this).data[idx]
    }
};
 
int main()
{
    Array a(10);
    a[1] = 1;  // OK: the type of a[1] is int&
    const Array ca(10);
    ca[1] = 2; // Error: the type of ca[1] is int
}

ref修飾子付きメンバ関数

暗黙的オブジェクトメンバ関数は、ref修飾子なし、lvalue ref修飾子 (パラメータリストの後のトークン&)、またはrvalue ref修飾子 (パラメータリストの後のトークン&&) を付けて宣言できます。オーバーロード解決中、クラスXのcv修飾子シーケンスを持つ暗黙的オブジェクトメンバ関数は次のように扱われます。

  • ref修飾子なし: 暗黙的オブジェクトパラメータはcv修飾されたXへのlvalue参照型であり、さらにrvalue暗黙的オブジェクト引数をバインドすることを許可されます。
  • lvalue ref修飾子: 暗黙的オブジェクトパラメータはcv修飾されたXへのlvalue参照型です。
  • rvalue ref修飾子: 暗黙的オブジェクトパラメータはcv修飾された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修飾とは異なり、ref修飾はthisポインタのプロパティを変更しません。rvalue ref修飾された関数内では、*thisはlvalue式として残ります。

(C++11以降)

[編集] 仮想関数および純粋仮想関数

非静的メンバ関数は仮想または純粋仮想として宣言できます。詳細については、仮想関数および抽象クラスを参照してください。

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

cv修飾子またはref修飾子なしで宣言された非静的非仮想メンバ関数について、その最初のパラメータが関数パラメータパックでない場合、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から)

[編集] 特殊メンバ関数

一部のメンバ関数は特殊です。特定の状況下では、ユーザによって定義されていなくても、コンパイラによって定義されます。それらは次のとおりです。

(C++11以降)
(C++11以降)

特殊メンバ関数は、比較演算子とともに(C++20以降)デフォルト化できる唯一の関数です。つまり、関数本体の代わりに= defaultを使用して定義できます (詳細はそれぞれのページを参照)。

[編集] 注釈

機能テストマクロ 規格 機能
__cpp_ref_qualifiers 200710L (C++11) ref 修飾子
__cpp_explicit_this_parameter 202110L (C++23) 明示的オブジェクトパラメータ (thisの推論)

[編集]

#include <exception>
#include <iostream>
#include <string>
#include <utility>
 
struct S
{
    int data;
 
    // simple converting constructor (declaration)
    S(int val);
 
    // simple explicit constructor (declaration)
    explicit S(std::string str);
 
    // const member function (definition)
    virtual int getData() const { return data; }
};
 
// definition of the constructor
S::S(int val) : data(val)
{
    std::cout << "ctor1 called, data = " << data << '\n';
}
 
// this constructor has a catch clause
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; // ctor's catch clause should always rethrow
}
 
struct D : S
{
    int data2;
    // constructor with a default argument
    D(int v1, int v2 = 11) : S(v1), data2(v2) {}
 
    // virtual member function
    int getData() const override { return data * data2; }
 
    // lvalue-only assignment operator
    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: assignment to lvalue
//  D(5) = d1; // ERROR: no suitable overload of 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 非静的メンバ関数が
囲むクラス名と同じ名前を持つことができるかどうか曖昧
明示的な名前の制限が追加されました

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)