Non-static member functions
非静的メンバ関数は、クラスの
メンバ指定
内で、
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以前では、これは非静的メンバ関数の唯一の種類であり、文献では「非静的メンバ関数」と呼ばれていました)。
目次 |
、
、
説明
任意の
関数宣言
が許可されており、非静的メンバー関数でのみ使用可能な追加の構文要素があります:
pure-specifiers
、cv-qualifiers
、ref-qualifiers、
final
および
override
指定子
(C++11以降)
、そして
メンバー初期化リスト
。
X
クラスの非静的メンバ関数は呼び出し可能です
X
のオブジェクトに対してクラスメンバアクセス演算子を使用する場合
X
のメンバー関数本体から直接
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 }
参照修飾子付きメンバ関数
暗黙のオブジェクトメンバ関数は、参照修飾子なし、左辺値参照修飾子(パラメータリスト後のトークン
注記:cv修飾とは異なり、参照修飾は
|
(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) |
- デストラクタ (C++20まで) プロスペクティブデストラクタ (C++20以降)
特殊メンバ関数 および 比較演算子 (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 | 非静的メンバー関数が外側のクラス名と同じ名前を持つことができるかどうかが曖昧 | 明示的な命名制限が追加された |