プライベート メソッドは常に Const にする必要がありますか?

関数の役割は何ですか?

関数は入力を受け取り、それらに基づいて出力を計算します。また、関数のインターフェイスを明確にするために、その入力と出力が何であるかを明確にすることがいかに重要であるかを確認しました.

C++ には、特定の規則を使用して入力と出力を表現する特定の種類の関数があります:クラスのプライベート メソッド 、クラスの実装をサブルーチンに編成するのに役立ちます。

実際、プライベート メソッドはクラスのデータ メンバーにアクセスできるため、理論的には、プライベート メソッドはクラスの任意のメンバーを取ることができます。 入力または出力として、プロトタイプには表示されません。

入力と出力を表示しないメソッドを制御するにはどうすればよいでしょうか?また、そのような制御を行う必要はありますか?

コード例では、クラス A を使用しましょう これには、いくつかのプライベート データ メンバーと、巧妙に doSomething と呼ばれるプライベート メソッドがあります。 .

そのヘッダーには次のものがあります:

// a.hpp

class A
{
public:
    void publicMethod();
private:
    Data1 member1;
    Data2 member2;
    Data3 member3;
    Data4 member4;
    Data5 member5;
    Data6 member6;

    void doSomething();
};

およびその実装ファイル:

// a.cpp

void A::publicMethod()
{
   // some code..

   doSomething(); // oops, what was the impact on the members?

   // more code...
}

このコードの問題は、publicMethod の観点から 、プライベート メソッド doSomething の呼び出しがどのような副作用をもたらすかはわかりません

この状況を明らかにする方法を見てみましょう。

一部のコードをクラスから移動

関数の入力と出力を明確にする方法はすでにわかっています。したがって、プライベート メソッドの入力についても明確にする 1 つの方法は、それを削除して、フリー関数に置き換えることです!このフリー関数はクラスの外にありますが、同じ実装ファイル内にあります:

// a.cpp

namespace
{
Data4 doSomething(Data1 const& data1, Data5 const& data5)
{
    // code that used to be in privateMethod
}
}

void A::publicMethod()
{
   // some code..

   member4 = doSomething(member1, member5); // we now see which parts of the class are impacted

   // more code...
}

この新しい free 関数は、クラス A のデータ メンバーには直接作用しません。 .代わりに、A データ メンバーを渡して呼び出し、返された値に基づいて他のデータ メンバーに作用します。

この操作の利点は、 publicMethod の観点から 、関数の呼び出しが member1 を使用することが非常に明確になりました と member5 、および member4 のみに影響します .これにより、プライベート メソッドであったものの入力と出力が明確になります。

クラスをバラバラにしないでください

場合によっては、プライベート メソッドに クラスの多くのメンバー が含まれる場合など 、この手法はあまり実用的ではありません:

// a.cpp

namespace
{

struct Outputs
{
    Data2 data2;
    Data4 data4;
};

Outputs doSomething(Data1 const& data1, Data3 const& data3, Data5 const& data5, Data6 const& data6)
{
    // code that used to be in the private method
}
}

void A::publicMethod()
{
   // some code..

   auto outputs = doSomething(data1, data3, data5, data6);
   member2 = outputs.data2;
   member4 = outputs.data4;

   // more code...
}

うわー、この種の場合、無料の関数を使用すると、プライベート メソッドの呼び出しよりも多くのコードが生成されます。

タプルを使用することで軽減できます:

// a.cpp

namespace
{

std::tuple<Data2, Data4> doSomething(Data1 const& data1, Data3 const& data3, Data5 const& data5, Data6 const& data6)
{
    // code that used to be in privateMethod
}
}

void A::publicMethod()
{
   // some code..

   std::tie(member2, member4) = doSomething(data1, data3, data5, data6);

   // more code...
}

それでも、これはかなりかさばる関数呼び出しです。

そのため、プライベート メソッドをフリー関数に抽出することが便利な場合もありますが、常に最適なオプションとは限りません。

少なくとも アウトプットについては明確にしてください

考えてみると、プライベート メソッドへの最初の呼び出しの問題は正確には何でしたか?

// a.cpp

void A::publicMethod()
{
   // some code..

   doSomething(); // what was the impact on the members?

   // more code...
}

呼び出し後、クラスで何が変更されたかについてはほとんどわかりません。そして、これが重要です。

実際、このメソッドの入力が何であるかを正確に知っていますか?正確ではありませんが、それらがデータ メンバーの一部であることは確かです (コードでグローバル変数が使用されている場合を除きます。これは別の問題です)。これは、クラスのメソッドであるという事実から導き出される妥当な量の情報です。

しかし、プライベート メソッドの副作用については、非常に正確に知る必要があります。 、 publicMethod の実行中に何が起こっているかを追跡します .

コンベンション

これを行う 1 つの方法は、2 つの側面を持つ規則に同意することです。

  • private メソッドは、クラスのすべてのデータ メンバーにアクセスできますが、それらを変更することはできません
  • 変更するメンバーは、メソッド パラメータとして渡す必要があります 、非 const 参照として。

このようにして、プライベート メソッドの呼び出しサイトは、この呼び出しによってどのデータが影響を受けるかを示します:

// a.cpp

void A::doSomething(Data2& data2, Data4& data4)
{
    // code that modifies data2 and data4...
}

void A::publicMethod()
{
   // some code..

   doSomething(member2, member4); // we know only member2 and member4 are impacted

   // more code...
}

上記の規則により、このコードは、プライベート メソッドが data2 のみを変更することを表しています。 および data4 .

しかし…出力は参照として渡されるべきではありませんよね?

出力は戻り値の型を介して関数から出てくる必要があり、非 const 参照として渡されるべきではないことがわかりました。では、非 const 参照によって変更されたメンバーを渡すという私たちのガイドラインは、この原則と矛盾しているのでしょうか?

実際、private メソッドの観点からは、それが変更するメンバーは出力ではありません。 .実際、それらが出力である場合、メソッドはそれらを作成して返します。

むしろ、メソッドはデータ メンバーを変更するため、関数がデータ メンバーを変更することによって何らかの方法で使用するため、データ メンバーも入力と見なすことができます。したがって、これらのメンバーはむしろ 入出力 の役割を果たします アウトプットだけではなく。そして、入出力を表現するための C++ の規則は、非 const 参照を使用することであることがわかりました。したがって、ここに矛盾はありません。

プライベート メソッドは const にする必要があります ?

プライベート メソッドがそのパラメータを使用してクラス データを変更することを強制する規則について同意する場合、どうすれば強制できますか ?

簡単な方法があります:プライベート メソッドは const にすることができます .この方法では、誤ってデータ メンバーを変更することはできませんが、データ メンバーから読み取って入力として使用することはできます。

void A::doSomething(Data2& data2) const // no silent access to members
{
   // code that modifies data2
}

void A::publicMethod() // not const
{
   // some code..

   doSomething(member2); // this modifies member2

   // more code...
}

しかし一方で、 const を持つ メソッドは、それを呼び出してもクラスのデータが変更されないことを表しています。そして、ここではまさにそれを行うためにそれを使用しているため、不快になる可能性があります.

私の見解では、その規則を使用するか、この場合は const を招集する必要があります。 const を使用しないようにするための技術的な成果物です。 ここ。この場合、誰もがプライベート メソッドから直接データ メンバーを変更しないように注意して、規約を手動で実施することに依存します。

この条約について、またはそれを施行する方法について意見はありますか?

関連記事:

  • 関数を機能させる