この質問で sbi と Eli Bendersky の回答を読んだ後、静的メンバー関数が何のためにあるのか疑問に思い始めました。
クラスのフレンドフリー関数は、静的メンバー関数ができることを何もできないはずですか? もしそうなら、なぜ/いつ、友達のないメンバー関数よりも静的メンバー関数を好むべきですか?
この質問で sbi と Eli Bendersky の回答を読んだ後、静的メンバー関数が何のためにあるのか疑問に思い始めました。
クラスのフレンドフリー関数は、静的メンバー関数ができることを何もできないはずですか? もしそうなら、なぜ/いつ、友達のないメンバー関数よりも静的メンバー関数を好むべきですか?
一般に:
プライベート メンバーへのアクセスを要求する
静的メンバー関数は、クラスのプライベート メンバーにアクセスできます。それが必要な場合は、静的メンバー関数を使用できます。アクセスを許可するには、とにかくヘッダーで宣言する必要があるため、フレンドではなくメンバーにすることもできます。シングルトンとして getInstance() メソッドを持つシングルトン、および静的ファクトリ メソッド createInstance() を使用して確実にヒープ上に作成されるクラスに対して、この方法で一般的に行われます。これらは両方とも、プライベート コンストラクターにアクセスする必要があります。
メタプログラミング
静的メンバー関数は、実際にどの関数が呼び出されるかを呼び出し時点で知らなくても、クラスを渡してそのメソッドを呼び出すことができるテンプレートのメタプログラミングに非常に適しています。これは一般に「コンパイル時ポリモーフィズム」と呼ばれ、メタプログラミングの重要な部分です。std::char_traits はこの原則に基づいています。
制限付きアクセス
プライベートな静的メンバー関数の一般的な使用は、クラスによってのみアクセスでき、プライベート メンバーへのアクセス自体を必要としないためだけに、静的メンバー関数の適切な使用法ではありません。これは、コンパイル ユニットの匿名名前空間で行う方が適切です。
ただし、静的メンバー関数が保護されている場合は、派生クラスによって呼び出される可能性がありますが、外部クラスによって呼び出されることはありません。
フレンド機能
operator<<
)静的メソッド:
Animal
であり、静的メソッドがCreate
である場合、 で呼び出す必要がありますAnimal::Create
。これはグローバル関数よりも優れており、ファクトリと「仮想コンストラクタ」を比較的自然な構文で実装できます。多くの場合、率直に言って、すべきではありません。無料の機能は非常に過小評価されています。
静的メンバーを使用することで得られる暗黙の「名前空間」(クラスが静的メンバーの名前空間に過ぎないふりをしている) は、私が考えることができる唯一の利点です。
静的関数メンバーに永続変数が必要な場合は、それと共に静的データ メンバーを持つ機能も役立つ場合があります。
手続き型のバックグラウンドを持ち、オブジェクト指向を理解していない人が静的関数を使用することが多いため、静的関数の使用に慎重になる人もいます。
ただし、静的メンバー関数を使用して実装するのが理にかなっている多くのデザイン パターンがあります。
例えば。シングルトン パターンとファクトリ パターンは私の頭の中でいくつか名前を付けます。実際、オブジェクトの作成を必要とするほとんどの構造パターンは、静的メンバー関数を必要とします。
static
あなたが正しく識別したように、メンバー関数に付加価値はありません。さらに悪いことに、実装の詳細に使用すると、(コンパイルに関して) 余分な依存関係が発生します。
匿名の自由関数でエミュレートできなかった唯一の用途は、アクセス、protected
つまり、親の静的関数にアクセスする派生クラスです。ただし、これは必須ではありません。代わりに、通常のメンバー関数にすることもできます (グローバル状態を持っていないと仮定します。それ以外の場合、静的/フレンドの区別は差し迫った問題ではありません)。
テンプレートのメタプログラミングでの関数の使用static
が呼び起こされました... しかし、これは内部型の問題と非常に似ています: デフォルトのバージョンを提供することを困難にします. 一方、適切に定義されたフリー関数 (型をポインターとして受け取る) は、テンプレート バージョンを提案できます。
struct some_traits
{
static void doStuff();
};
// versus
struct some_traits {};
void doStuff(some_traits*);
// and the default: void doStuff(...);
そしてもちろん、メンバー関数がユーザーにより多くの柔軟性を提供するのに、なぜこれが静的関数であるべきなのかという疑問が常にあります。この趣旨で、私は標準委員会がAllocator
コンセプトで行った動きを引用します: ステートフル アロケータが承認されるようになりました。これにより、特定のノードをmap
ヒープ全体に分散させるのではなく、同じページにパックする機会が得られます。
最後に、インターフェースの問題があります。しかし、Sutter が同じヘッダーで定義されたクラスとフリー関数の両方がこのクラスのパブリック インターフェイスを構成することを提唱してから長い時間が経ちました => それが ADL の目的です! したがって、「良い習慣」というよりも、古い OO プログラマーを慰めるためのものです。
static
本当に、メンバー関数を使用しても何のメリットもありません。実際のケースを提案するために、反対のことを考えてほしいと思います。