web-dev-qa-db-ja.com

いつ/なぜクラスで関数をプライベートにするのですか?

関数privateを作成する必要があるのはいつですか。なぜ良いアイデアなのですか?

22
Ramilol

他のオブジェクトやクラスが関数にアクセスする必要がない場合、クラス内から呼び出す場合は、関数privateを作成する必要があります。

最小特権の原則に固執する、絶対に必要な変数/関数へのアクセスのみを許可します。この基準に適合しないものはすべてprivateである必要があります。

28
Jacob Relkin

通常、ヘルパー関数をprivateにします。しかし、helperとは何か曖昧なようです。例を挙げましょう。次のクラスがあるとしますSample;公開関数はほとんど公開されていませんが、そのうちの1つはDoWork()などです。この関数は1つのパラメーターを取ります。ただし、パラメーターが常に有効であるとは想定されていないため、firstは、関数の先頭に多数のコードがあるパラメーターの有効性をチェックします。このようなもの:

_class Sample
{
   public:
      void DoWork(SomeClass param)
      {
               /*
                *lots of code related to validation of param
                */  

                //actual code that operates on the param 
                //and other member data IF the param is valid
      }
};
_

Paramの検証に関連する多くのコードを記述したため、関数が扱いにくくなり、読みにくくなります。そのため、この検証コードを関数IsValidParam()に移動し、DoWork()からこの関数を呼び出し、パラメーターparamを渡します。このようなもの:

_class Sample
{
   public:
      void DoWork(SomeClass param)
      {       
            if ( IsValidParam(param))       
            {
                //actual code that operates on the param 
                //and other member data IF the param is valid
            }
      }
};
_

きれいに見えますか?

さて、あなたはクラスのどこかにIsValidParam()を記述しましたが、あなたが今直面している問題は、この関数をpublicにしますか?この関数がDoWork()のような他の関数によってonly使用されている場合、IsValidParam()publicにします意味がありません。この関数をprivateにすることにしました。

_class Sample
{
   public:
      void DoWork(SomeClass param)
      {       
            if ( IsValidParam(param))       
            {
                //actual code that operates on the param 
                //and other member data IF the param is valid
            }
      }
  private:
      bool IsValidParam(SomeClass param)
      {
          //check the validity of param.
          //return true if valid, else false.
      }
};
_

この種類の関数(IsValidParam)はprivateである必要があります。これらの関数ヘルパー関数を呼び出します。

この説明がお役に立てば幸いです。

21
Nawaz

OOPの創設の原則の1つはカプセル化です。これは、オブジェクトがどのように機能するかについての機能性がそのオブジェクトの内部に保持されるところです。アイデアは、それがそうである場合、コードがオブジェクトを使用する方が簡単であるということです電子レンジを購入するようなものです-電子レンジの使い方ではなく、電子レンジの使い方を知る必要があるだけです。

OOPでも同じアプローチを取る必要があります。オブジェクトをプライベートに維持するために必要なすべてのものを保持します。オブジェクトを完全に使用するために必要なものだけを作成します。

6
Jonathan Wood

クライアントコードでのクラスの使用方法を考慮してクラスを設計している場合、publicとおそらくprotectedのメンバーで構成されるインターフェースを必然的に派生させることになります。

privateメンバーは、これらのパブリック/保護されたメンバーをサポートおよび有効にする関数とデータです。 private関数は、非privateメンバーが必要とするコードを因数分解および/またはモジュール化/構造化して、それらの実装の冗長性を減らし、理解しやすくする必要があります。

要約すると、クライアントコードによる直接の使用を目的としておらず、private以外のメンバーをサポートするためにのみ存在する場合は、メンバーをprivateにします。

2
Tony Delroy

どのくらい純粋になりたいですか? :)

この質問に対する正しい答えは、不変条件の維持に関連しています。これを行う正しい方法はかなり複雑です。

基本クラスで、クラスへのアクセスのwholeを提供するパブリックメソッドを定義します。これらの方法はすべて具体的でなければなりません。ここで重要なのは、これらの関数を呼び出す前後にパブリックインバリアントが保持されると想定されていることです。これらの関数は互いに呼び出してはならず、保護されたプライベートメソッドのみを呼び出します。これらの関数は公理的である必要があります。これらは、目的のセマンティクスを取得するために必要なかなり最小限のセットである必要があります。

これらのメソッドを使用して実行できるほとんどの計算は、グローバルまたは少なくともパブリック静的メンバーである必要があります。

また、派生クラスの表現に応じて詳細を実装するためのフックである純粋な仮想メソッドを提供します。ベースの仮想関数はプライベートである必要があります。ここでの通常のアドバイス(公開)は完全に間違っています。仮想関数は実装の詳細です。 1つの例外:仮想デストラクタはパブリックでなければなりません。

プライベートヘルパー関数もベースに配置できます。

ベースにも保護されたメソッドがあると便利な場合があります。これらはプライベートヘルパーまたは仮想関数を呼び出します。上記のとおり:保護されたメソッドは、保護されたメソッドまたはパブリックメソッドを呼び出さないでください。保護された関数は、各呼び出しの前後で、パブリック関数よりも弱い不変を維持します。

通常、プライベート関数は非常に弱い不変量を維持します。

この厳密な階層の理由は、オブジェクトの不変条件が正​​しく維持されるようにするためです。

ここで、派生クラスで実装を提供します。理想的には、ここでの仮想関数はinvisibleであり、単なるプライベートよりも強い条件です。これらの仮想関数は、派生クラスではまったく呼び出されません。 only許可されたアクセスは、ベースの保護された機能を介して行われます。

デストラクタを含む派生クラスのすべてのメソッドはプライベートである必要があります。コンストラクターはパブリックでなければなりませんが、それらはクラスのメソッドではありません。

これらのルールを完全に理解するには、不変条件について注意深く考える必要があります。パブリックインバリアントは、パブリックメソッドを呼び出す前にholdと見なすことができ、終了後はholdが必要です。したがって、これらの関数はパブリック関数の開始と終了の間の表現を変更するために使用され、必然的にパブリック不変式を壊すため、クラス内から派生したクラスやそのクラスからそのような関数を呼び出すことはできません。パブリック関数を呼び出さないでください。

同じ引数が保護された関数に適用されます:関数は、より弱い不変条件を持つ関数のみを呼び出すことができます

仮想関数は、基本クラスのパブリックラッパーから常にpublicによって呼び出され、操作のシーケンスがパブリックインバリアントを壊し、インバリアントを壊してパブリックに戻ることによって中断されることがないようにします。仮想セット自体は、任意の表現が持つ必要のある不変構造を表します。これを行うことにより、パブリッククライアントの計算を実行するための表現のすべての操作をベースに抽象化できます。

実際には、これらの規則は通常は従われません。なぜなら、それらはしばしば些細なラッパーを生成し、それは記述および維持するための多くの追加コードであるためです。したがって、仮想関数は、原則として完全かつ完全に間違っている場合でも、最終的には公開されることがよくあります。

1
Yttrill

関数またはクラスを作成する前に、その関数またはクラスのスコープがグローバルであってもローカルであっても理解する必要があります。

例:「ConnectionString()」。すべてのデータベース接続には "ConnectionString()"が必要なので、その宣言されたパブリックです。

0
Justinonday

private:このクラスでのみ使用され、他のクラスや派生クラスでは使用されません。
protected:このクラスおよびおそらく派生クラスで使用されますが、他のクラスでは使用されません。
public:他のクラス、このクラス、および派生クラスによって使用されます。

プライベートと保護のどちらを選択するかは難しい。したがって、派生クラスで必要になる可能性が1%ある場合は、常に関数を保護します。

0
wqking