29

これは本当に良い形式/ベストプラクティスの問題です。私はC++の構造体を使用して、値を取得/設定するだけの大量のアクセサメソッドを使用してクラスを作成するのではなく、基本的にデータを保持するように設計されたオブジェクトを形成します。例えば:

struct Person {
    std::string name;
    DateObject dob;
    (...)
};

そこにさらに20個の変数があると想像すると、これをプライベートメンバーと40個のアクセサーを含むクラスとして作成するのは管理が面倒で、私には無駄に思えます。

ただし、データに最小限の機能を追加する必要がある場合もあります。例では、生年月日に基づいて、年齢も必要になることがあるとしましょう。

struct Person {
    std::string name;
    DateObject dob;
    (...)
    int age() {return calculated age from dob;}
}

もちろん、複雑な機能の場合はクラスを作成しますが、このような単純な機能の場合、これは「悪い設計」ですか?クラスを使用する場合、データ変数をパブリッククラスメンバーとして保持するのは悪い形式ですか、それともそれを受け入れて多数のアクセサーメソッドを使用してクラスを作成する必要がありますか?クラスと構造体の違いを理解しています。ベストプラクティスについて質問しているだけです。

4

7 に答える 7

27

ここで考慮すべき2つの重要な設計原則があると思います。

  1. そのクラスに不変条件がある場合は、インターフェイスを介してクラスの表現を非表示にします。

    そのクラスに無効な状態がある場合など、クラスには不変条件があります。クラスは常に不変条件を維持する必要があります。

    Point2D幾何学的点を表すタイプを考えてみましょう。これはstruct、パブリックメンバーxyデータメンバーだけで行う必要があります。無効点などはありません。xと値のすべての組み合わせyは完全に問題ありません。

    の場合、Person不変量があるかどうかは、目前の問題に完全に依存します。空の名前などを有効な名前だと思いますか?Person生年月日はありますか?あなたの場合、答えはイエスだと思います。あなたのクラスはメンバーを公開しておくべきです。

    参照:クラスは不変条件を適用する必要があります

  2. 非フレンド非メンバー関数はカプセル化を改善します。

    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;
}
于 2013-03-22T14:43:45.663 に答える
6

C ++では、Structsはクラスであり、唯一の違いは(少なくとも、私が考えることができる)、Structsのメンバーはデフォルトでパブリックですが、クラスではプライベートです。これは、Structsをそのまま使用することは完全に許容できることを意味します-この記事ではそれをうまく説明しています。

于 2013-03-22T14:24:37.573 に答える
1

C ++では、構造体とクラスの唯一の違いは、構造体がデフォルトで公開されていることです。適切なガイドラインは、構造体をプレーンオールドデータ(POD)として使用し、データのみを保持し、より多くの機能(メンバー関数)が必要な場合にクラスを使用することです。

クラスにパブリック変数を含めるだけなのか、メンバー関数を使用するのか、まだ疑問に思われるかもしれません。次のシナリオを検討してください。

プライベート変数のゲッターにすぎないA関数を持つクラスがあるとしましょう。GetSomeVariable

class A
{
    double _someVariable;

public:
    double GetSomeVariable() { return _someVariable; }
};

20年後にその変数の意味が変わり、たとえば0.5を掛ける必要がある場合はどうでしょうか。ゲッターを使用する場合、それは簡単です。変数に0.5を掛けたものを返すだけです。

    double GetSomeVariable() { return 0.5*_someVariable; }

これにより、保守性と変更性が向上します。

于 2013-03-22T14:29:50.070 に答える
1

データホルダーが必要な場合は、get/setメソッドを使用しないstructをお勧めします。

この場合のように、それ以上の場合は「人」。

  1. 実世界の実体をモデル化し、
  2. 明確な状態と振る舞いを持っています、
  3. 外界と相互作用し、
  4. 他のエンティティとの単純/複雑な関係を示し、
  5. それは時間とともに進化するかもしれません、

それなら、それはクラスの完璧な候補です。

于 2013-03-22T14:33:09.693 に答える
0

「データを運ぶパッシブオブジェクトにのみ構造体を使用してください。それ以外はすべてクラスです。」

グーグルガイドラインと言う、私はそれをこのようにして、それが良いルールだと思う。それに加えて、あなたはあなた自身の語用論を定義することができるか、それが本当に理にかなっているならこの規則から逸脱することができると思います。

于 2013-03-22T14:26:51.450 に答える
0

ここで聖戦を引き起こしたくありません。私は通常、次のように区別します。

  • PODオブジェクト(つまり、公開された動作のないデータのみ)の場合、内部をパブリックとして宣言し、それらに直接アクセスします。ここではキーワードの使い方structが便利で、オブジェクトの使い方のヒントにもなります。
  • 非PODオブジェクトの場合、内部をプライベートとして宣言し、パブリックゲッター/セッターを定義します。classこのような場合、キーワードの使用はより自然です。
于 2013-03-22T14:31:47.973 に答える
0

一部の混乱を解消するためだけに!そして簡単にピッキング!ここにいくつかのポイントがあります!

構造体で!カプセル化可視性の演算子(プライベートまたはパブリックにする)を持つことができます!クラスと同じように!

したがって、一部の人が言う、またはオンラインで見つけるかもしれないという声明は、次のようになります。違いの1つは、構造には可視性演算子がなく、データを非表示にする機能がないということです。

クラスと同じようにメソッドを持つことができます!

以下のコードを実行してください!そして、あなたはそれがすべてうまくコンパイルされることを確認することができます!そして、すべてうまく実行します!そして、構造体全体がクラスと同じように機能します!

主な違いは、可視性モードのデフォルト設定だけです。

構造物はそれを公開しています!デフォルトでプライベートをクラス化します!

#include<iostream>
#include<string>

using namespace std;

int main(int argv, char * argc[]) {
    struct {
        private:
            bool _iamSuperPrivate = true;
            void _sayHallo() {
                cout << "Hallo mein Bruder!" << endl;
            }
        public:
            string helloAddress = "";
            void sayHellow() {
                cout << "Hellow!" << endl;
                
                if (this->helloAddress != "") {
                    cout << this->helloAddress << endl;
                }

                this->_sayHallo();
            }
            bool isSuperPrivateWorking() {
                return this->_iamSuperPrivate;
            }
    } testStruct;

    testStruct.helloAddress = "my Friend!";
    testStruct.sayHellow();

    if (testStruct.isSuperPrivateWorking()) {
        cout << "Super private is working all well!" << endl;
    } else {
        cout << "Super private not working LOL !!!" << endl;
    }

    return 0;
}

ここに画像の説明を入力してください

記憶の中でそれらは同じです!

私は自分自身をチェックしませんでした!しかし、同じことをすると言う人もいます!コンパイルされたアセンブリコードは、構造体クラスの間で同じになります!(チェックする!)

任意のクラスを取得し、名前をtypedef structに変更します!コードは引き続き同じように機能することがわかります。

class Client {

}

Client client(...);

=>

typedef struct Client {
 ....
} Client;

Client client(...);

そうすれば、すべて同じように機能します!少なくとも私はそれがgccで行われることを知っています!

あなたはテストすることができます!あなたのプラットフォームで!

于 2021-06-05T21:40:41.453 に答える