4

クラスに public フィールドを持つことは悪い考えだと考えられていることは知っています。しかし、クラスに多数の階層データ構造とフィールドが含まれている場合、どのようなアプローチが最適でしょうか? 例えば:

class A {B d1; C d2; D d3;}
class B {E d4; F d5;}
class E {G d6; int d7;}

C では、ptr_to_A->d1.d4.d7 などのようなデータ構造にアクセスするのは非常に簡単です。

C++ でセッターとゲッターを使用する場合、A.get_d1().get_d4().get_d7() のような式は便利ではないようで、参照を返すことを強制します。一部の構造体は非常に大きいため、値で返すのはひどい考えに思えます。

これらの場合、どのアプローチまたはコーディング スタイルを使用しますか? たぶん、セッター/ゲッターを取り除き、これらのフィールドを公開しますか?

4

3 に答える 3

5

クラスに public フィールドを持つことは悪い考えだと考えられていることは知っています。

これは、過去 10 年間の Java 開発から得られた包括的な声明です。メンバーをパブリックにするかプライベートにするかは、メンバーごとに検討する必要があります。パブリック データ メンバーが正しい考えである場合があります。次の質問を検討してください。

  1. このメンバーに対して不変条件を維持する必要がありますか?
  2. このメンバーは無効な値を持つことができますか?
  3. インターフェイスでこのメンバーの代替表現を提供する必要がありますか?

上記の質問のいずれかに対する答えが「はい」の場合、おそらく getter を使用する必要があります。

また、メンバーを個別に設定することが実際に意味があるかどうかも検討してください。おそらく、コンストラクターでメンバーを設定する必要があり、それらのメンバーを変更する他のインターフェイスを提供したい場合があります。

C++ でセッターとゲッターを使用する場合、A.get_d1().get_d4().get_d7() のような式は便利ではないようです。

データ構造がかなり深い入れ子になっていることはそれほど珍しいことではありませんが、通常、特定のコードの部分を深く掘り下げる必要はありません。もしそうなら、それはおそらく、その単一の責任を超えて、必要以上のことをしていると思います. d7ただし、オブジェクトから取得することが一般的なタスクである場合はA、おそらくAそのインターフェイスで公開する必要があります。

int A::get_d7 {
  return get_d1().get_d4().get_d7();
}

一部の構造体は非常に大きいため、値で返すのはひどい考えに思えます。

実際、最新の C++ では、これはまったく問題になりません。値による受け渡しは、オブジェクト受け渡しのデフォルト モードと見なす必要があります。これは、一時オブジェクトを移動できるようになったためです。これは、本質的に非常に効率的なコピー形式です。

于 2013-03-28T18:52:44.103 に答える
3

私のコーディング スタイルでは、クラスは public の「生の」データ メンバーを公開するべきではなく、getter と setter のみを公開する必要があります (単純な 1 行のメソッドであっても)。

これは、コードが将来的にアップグレードされる可能性があり、単一行の方法がより複雑なものに拡張される可能性があるためです (または、いくつかのデバッグのみのビルド機能を追加して、いくつかの不変条件をチェックするなど)。クライアントに対して一貫したインターフェイス (「生の」データ メンバーを公開する場合、これは不可能です)。

接頭辞の使用を避けget_()、データ メンバーを単純な (なしのget_...) 名前を持つ「プロパティ」と見なすことができます。

class Shape
{
public:
  ....

  COLORREF Color() const // Just Color() i.e. the property name, without get_...
  {
     return m_color;
  }

private:
  COLORREF m_color;
};

そして、次のようなクライアント コードを記述します。

Shape s;
COLORREF someColor = s.Color();

それは私にはうまく見えます。

セッターの場合、次のような構文を使用できます。

Shape& Color(COLORREF color)
{
    m_color = color;
    return *this;
}

次のようなクライアント コードを記述します。

Shape s;
s.Color(...).Draw(); // set color and draw shape

COLORREFプロパティの型が(32 ビットの)よりも複雑な場合はDWORD、次のようなパターンを使用できます。

std::wstring Name() const // getter
{
    return m_name;
}

Shape& Name(std::wstring name) // setter
{
    // Pass by value and move from the value (C++11 move semantics)
    m_name = std::move(name);

    return *this;
}
于 2013-03-28T18:51:22.327 に答える
1

クラスを純粋なデータ構造として使用しているだけで、カプセル化するデータに関連する動作structがない場合は、代わりに a を使用してフィールドに直接アクセスします。Bjarne Stroustrup は、このアプローチを推奨しています。これは、 a を使用classしてすべてのメンバーを として宣言することと同じですpublicが、代わりに a と呼ぶと、struct単なるデータの収集にすぎないことが明確になります。

データを格納する以上のことを行う場合は、ゲッターとセッターを使用します。

C++ でセッターとゲッターを使用する場合、A.get_d1().get_d4().get_d7() のような式は便利ではないようで、参照を返すことを強制します。一部の構造体は非常に大きいため、値で返すのはひどい考えに思えます。

いいえ、参照または値のどちらで返すかを選択できます。

于 2013-03-28T18:51:14.053 に答える