これは本当に良い形/ベストプラクティスの問題です。 C++の構造体を使用して、値を取得/設定するだけの処理を行う多数のアクセサメソッドを持つクラスを作成するのではなく、基本的にデータを保持するように設計されたオブジェクトを作成します。例えば:
struct Person {
std::string name;
DateObject dob;
(...)
};
さらに20個の変数を想像すると、プライベートメンバーと40個のアクセサーを持つクラスとしてこれを記述するのは管理が面倒で、私には無駄に思えます。
ただし、データに何らかの最小限の機能を追加する必要がある場合もあります。この例では、dobに基づいて年齢も必要になる場合があるとします。
struct Person {
std::string name;
DateObject dob;
(...)
int age() {return calculated age from dob;}
}
もちろん、複雑な機能についてはクラスを作成しますが、このような単純な機能については、これは「悪い設計」ですか?クラスを使用する場合、データ変数をパブリッククラスメンバとして保持するのは悪い形式ですか、またはそれを受け入れて一連のアクセサメソッドを持つクラスを作成するだけですか?クラスと構造体の違いを理解しているので、ベストプラクティスについて質問しています。
ここで考慮すべき2つの重要な設計原則があると思います。
そのクラスに不変条件がある場合、インターフェースを介してクラスの表現を非表示にします。
クラスに無効な状態などがある場合、クラスには不変式があります。クラスは常に不変式を維持する必要があります。
2D幾何学的点を表すPoint
タイプを考えてみましょう。これは、パブリックstruct
およびx
データメンバーを持つy
である必要があります。無効なポイントなどはありません。 x
値とy
値のすべての組み合わせは完全に問題ありません。
Person
の場合、不変式があるかどうかは手元の問題に完全に依存します。空の名前などを有効な名前と見なしますか? Person
には誕生日がありますか?あなたの場合、答えはイエスだと思うし、あなたのクラスはメンバーを公開しておくべきだ。
非友達の非メンバー関数はカプセル化を改善します。
age
関数をメンバー関数として実装する必要はありません。 age
の結果は、Person
のパブリックインターフェイスを使用して計算できるため、メンバー関数になる理由はありません。 Person
と同じネームスペースに配置して、引数依存のルックアップで見つけられるようにします。 ADLで見つかった関数は、そのクラスのインターフェイスの一部です。プライベートデータにはアクセスできません。
それをメンバー関数にして、ある日、プライベート状態をPerson
に導入した場合、不必要な依存関係になります。突然age
は必要以上にデータにアクセスできます。
だからここに私がそれを実装する方法があります:
struct Person {
std::string name;
DateObject dob;
};
int age(const Person& person) {
return calculated age from person.dob;
}
C++では、Structsはクラスであり、onlyの違い(少なくとも私が考えることができる)は、Structsのメンバーはデフォルトでパブリックであるが、クラスではプライベートです。これは、そのまま構造体を使用することは完全に受け入れられることを意味します- この記事 はそれをうまく説明しています。
C++では、構造体とクラスの唯一の違いは、構造体がデフォルトで公開されていることです。優れたガイドラインは、データを保持し、より多くの機能(メンバー関数)が必要な場合にクラスを使用するプレーンオールドデータ(POD)として構造体を使用することです。
クラスにパブリック変数のみを含めるのか、メンバー関数を使用するのか疑問に思うかもしれません。次のシナリオを検討してください。
プライベート変数の単なるゲッターである関数A
を持つクラスGetSomeVariable
があるとしましょう:
class A
{
double _someVariable;
public:
double GetSomeVariable() { return _someVariable; }
};
20年後、その変数の意味が変わり、0.5を掛けなければならないとしたらどうでしょうか。ゲッターを使用する場合は簡単です。 0.5を掛けた変数を返すだけです:
double GetSomeVariable() { return 0.5*_someVariable; }
これにより、メンテナンスが容易になり、変更が簡単になります。
データホルダーが必要な場合は、get/setメソッドを持たないstructをお勧めします。
この場合のように、「Person」など、他にもある場合。
それはクラスの完璧な候補です。
「データを運ぶパッシブオブジェクトにのみ構造体を使用します。他のすべてはクラスです。」
google guidlines と言うと、私はこのようにして、良いルールを見つけます。それに加えて、あなたはあなた自身の語用論を定義するか、それが本当に理にかなっているならこの規則から逸脱することができると思う。
ここで聖戦を輝かせたくありません。私は通常、このように区別します:
struct
キーワードの使用はここで便利であり、オブジェクトの使用のヒントとしても機能します。class
キーワードの使用はより自然です。