web-dev-qa-db-ja.com

なぜプライベートメンバー関数をヘッダーに入れるのですか?

C++ヘッダーにプライベートメンバー変数を配置する理由の答えは、インスタンスが宣言された時点でクラスのサイズがわかっている必要があるため、コンパイラーはスタック内を適切に移動するコードを生成できるためです。

ヘッダーにプライベートメンバーを配置する必要があるのはなぜですか?

しかし、クラス定義でプライベート関数を宣言する理由はありますか?

代替案は基本的には簡単なイディオムですが、余分な間接参照はありません。

この言語機能は歴史的なエラー以上のものですか?

16
Praxeolitic

プライベートメンバー関数はvirtualであり、C++(vtableを使用する)の一般的な実装では、クラスのすべてのクライアントが特定の順序と仮想関数の数を知る必要があります。これは、1つ以上の仮想メンバー関数がprivateであっても適用されます。

コンパイラの実装の選択は言語仕様に影響を与えないため、これは「馬の前にカートを置く」のように見えるかもしれません。ただし、実際には、C++言語自体は、vtableを使用する実用的な実装( Cfront )と同時に開発されました。

11
Greg Hewgill

メソッドをその定義外のクラスに追加することを許可した場合、それらは、誰でも、任意のファイルでanywhereを追加できます。

これにより、すべてのクライアントコードにプライベートおよび保護されたデータメンバーへのささいなアクセスがすぐに与えられます。

クラスの定義が完了したら、一部のファイルを拡張するために作成者から特別な祝福を受けているとマークする方法はありません。フラットな翻訳単位しかありません。したがって、特定のメソッドのセットが公式である、またはクラスの作成者から祝福されていることをコンパイラに伝える唯一の合理的な方法は、クラス内でそれらを宣言することです。


C++でメモリに直接アクセスできることに注意してください。つまり、クラスと同じメモリレイアウトでシャドウタイプを作成し、独自のメソッドを追加して(またはすべてのデータをパブリックにして)、reinterpret_cast。または、私はあなたのプライベート関数のコードを見つけるか、それを分解することができます。または、シンボルテーブルで関数アドレスを検索し、またはを直接呼び出します。

これらのアクセス指定子は、これらの攻撃を防ぐことはできません。これは不可能だからです。それらは、クラスがどのように使用されることになっているのかを示すだけです。

14
Useless

受け入れられた回答はvirtualプライベート関数についてこれを説明しますが、それは質問の特定の1つの側面のみに回答します。これはOPが要求したものよりもかなり制限されています。したがって、言い換える必要があります:ヘッダーで非仮想プライベート関数を宣言する必要があるのはなぜですか?

別の答えは、クラスが1つのブロックで宣言されなければならないという事実を引き起こします-その後、それらはシールされて追加できません。これは、ヘッダーでプライベートメソッドを宣言することを省略し、それを別の場所で定義しようとすることによって行います。いいポイント。クラスの一部のユーザーが他のユーザーが監視できない方法でクラスを拡張できるのはなぜですか?プライベートメソッドはその一部であり、これから除外されていません。しかし、なぜ含まれているのかを尋ねると、少しトートロジーのように見えます。クラスのユーザーがそれらについて知っている必要があるのはなぜですか?それらが表示されない場合、ユーザーは何も追加できず、ねえプレストです。

したがって、デフォルトでプライベートメソッドを含めるだけでなく、特定のポイントを提供して、ユーザーに見えるようにするという答えを提供したいと思いました。パブリック宣言を必要とする非仮想プライベート関数の機構的な理由は、その理論的根拠の一部として Herb SutterのGotW#100(Pimplイディオムについて) に示されています。ここではPimplについては説明しません。みんな知っていると思います。しかし、ここに関連するビットがあります:

C++では、ヘッダーファイルのクラス定義のいずれかが変更された場合、そのクラスのユーザーがアクセスできないプライベートクラスメンバーのみが変更された場合でも、そのクラスのすべてのユーザーを再コンパイルする必要があります。これは、C++のビルドモデルがテキストのインクルードに基づいていること、およびC++が呼び出し側がプライベートメンバーによって影響を受ける可能性があるクラスについて2つの主要なことを知っていると想定しているためです。

  • サイズとレイアウト:[メンバーと仮想関数の-自明でパフォーマンスに優れていますが、ここにいる理由はありません]
  • Functions:呼び出しコードは、クラスのメンバー関数への呼び出しを解決できなければなりません非プライベート関数によるオーバーロード—プライベート関数の方が一致する場合、呼び出しコードはコンパイルに失敗します。 (C++は、安全上の理由から、アクセシビリティチェックの前に過負荷解決を実行するように意図的に設計を決定しました。たとえば、関数のアクセシビリティをプライベートからパブリックに変更しても、正当な呼び出しコードの意味は変更されないはずです。)

もちろん、サッターは委員会のメンバーとして非常に信頼できる情報源であるため、サッターはそれを見ると「意図的な設計決定」を知っています。また、セマンティクスの変更や誤ってアクセシビリティーを無効にすることを回避する方法として、プライベートメソッドのパブリック宣言を要求するという考えは、おそらく最も説得力のある根拠です。ありがたいことに、今までは全体的にかなり無意味だったようです!

9
underscore_d

これを行う理由は2つあります。

まず、アクセス指定子はコンパイラ用であり、実行時には関係がないことを理解してください。スコープ外のプライベートメンバーにアクセスすると、compileエラーが発生します。

簡潔

1行または2行の短い関数を考えます。他の場所でのコードの複製を減らすために存在します。これは、アルゴリズムなどの多くの方法を1か所で変更するのではなく、変更することができるという利点もあります(並べ替えアルゴリズムの変更など)。

ヘッダーに1行か2行の簡単な行があるのでしょうか、それとも関数プロトタイプとそこに実装があるのでしょうか。ヘッダーで見つけるのは簡単です。短い関数の場合、個別に実装する方がはるかに冗長です。

もう一つの大きな利点があります、それは...

インライン関数

プライベート関数はインライン化できる場合があり、これは必然的にそれがヘッダーにあることを必要とします。このことを考慮:

class A {
  private:
    inline void myPrivateFunction() {
      ...
    }

  public:
    inline void somePublicFunction() {
      myPrivateFunction();
      ...
    }
};

プライベート関数はパブリック関数と共にインライン化できますinlineキーワードは技術的には suggestion であり、要件ではないため、コンパイラーの裁量で行われます。

4
user22815

ヘッダーファイルにプライベートメソッドを含めるもう1つの理由:パブリックインラインメソッドが1つまたは複数のプライベートメソッドを呼び出す以上の場合はありません。ヘッダーにプライベートメソッドがあることは、パブリックメソッドの呼び出しをプライベートメソッドの実際のコードに完全にインライン化できることを意味し、インライン化はプライベートメソッドの呼び出しで停止しません。異なるコンパイルユニットからであっても(そしてパブリックメソッドは通常が異なるコンパイルユニットから呼び出されます)。

もちろん、プライベートメソッドを含むすべてのメソッドを認識していないと、コンパイラがオーバーロードの解決に関する問題を検出できないという理由もあります。

2
gnasher729

これらの関数がプライベートメンバーにアクセスできるようにするためです。それ以外の場合は、とにかくヘッダーでそれらをfriendする必要があります。

関数がクラスのプライベートメンバーにアクセスできる場合、プライベートは役に立ちません。

0
ratchet freak