2

Andrew Koenig と Barbara E. Moo による「Accelerated C++」を読んだことによる別の質問で、以前の例を使用して、コンストラクター (5.1) に関する章にいます。

あの人たちは書く

2 つのコンストラクターを定義する必要があります。最初のコンストラクターは引数をとらず、空のStudent_infoオブジェクトを作成します。2 つ目は、入力ストリームへの参照を取得し、そのストリームから生徒のレコードを読み取ることによってオブジェクトを初期化します。

Student_info::Student_info(istream& is) {read(is);}2番目のコンストラクターとして使用する例につながります

実際の作業を read 関数に委譲します。[...] read はすぐにこれらの変数に新しい値を与えます。

Student_infoクラスは

class Student_info {
public:
    std::string name() const (return n;}
    bool valid() const {return !homework.empty();}
    std::istream& read(std::istream&);

    double grade() const;
private:
    std::string n;
    double midterm, final;
    std::vector<double> homework;
};

はすでにクラスのread下の関数として定義されているため、2 番目のコンストラクターを使用する必要があるのはなぜですか?この二重の作業ではありませんか? 両方とも既に定義されているため、デフォルトのコンストラクターを使用してから関数を使用しないのはなぜですか?Student_info

4

2 に答える 2

5

それどころか、クラスをインスタンス化する呼び出し元のオブジェクトの初期化を簡素化するのは、二重の作業ではありません。

毎回単一のコンストラクターでクラスを作成する場合

std::istream is = std::cin;
Student_info si();
si.read(is);
// si.foo();
// si.bar();
// si.baz();

コンストラクターで実行できる他の操作を追加できるかもしれません。したがって、クラスをインスタンス化する必要があるときに、それらを再度書き込む必要はありません。10個のインスタンスを作成する場合は、次のように記述する必要があります。

(10 -1 =)さらに9行あり、これはOOPにとって適切なアプローチではありません

Student_info::Student_info(istream& is) 
{
    read(is);
    //foo();
    //bar();
    //baz();
}

しかし、上記のように2つのコンストラクターを定義すると、次のようなクラスを使用できます。

std::istream is = std::cin;
Student_info si(is);

OOPの主な目標の1つは、自己反復ではなく再利用可能なコードを作成することであり、もう1つの目標は、関心の分離です。多くの場合、オブジェクトをインスタンス化する人は、クラスの実装の詳細を知る必要はありません。

サンプルのread関数は、コンストラクター内で呼び出されたときにプライベートにすることができます。これは、OOPカプセル化の別の概念に到達します

最後に、これは二重の作業ではなく、ソフトウェア設計のための優れたアプローチです。

于 2013-03-22T07:33:03.570 に答える
1

私の質問は、read が既に Student_info クラスの関数として定義されているため、なぜ 2 番目のコンストラクターを使用する必要があるのか​​ということです。これは二重の作業ではありませんか?

2 番目のコンストラクターは、呼び出し元から引数を受け取り、それをread関数に渡します。Student_infoこれにより、をで直接インスタンス化できますstd::istream

std::istream is = ....;
Student_info si(is); // internally calls read(is)

とは対照的に

std::istream is = ....;
Student_info si;
si.read(is);     // how could we use is if this call isn't made? Now we have to read some docs...

両方とも既に定義されているため、デフォルトのコンストラクターを使用してから関数を使用しないのはなぜですか?

最初にオブジェクトを作成してから初期化するよりも、一貫性のある有用な状態になるようにオブジェクトを作成する方がよいためです。これは、オブジェクトのユーザーが、モノを使用できるかどうか、または最初に初期化する必要があるかどうかについて心配する必要がないことを意味します。たとえば、この関数は への参照を受け取りますStudent_info

void foo(const Student_into& si)
{
  // we want to use si in a way that might require that it has been
  // initialized with an istream
  si.doSomethingInvolvingInputStream(); // Wait, what if the stream hasn't been read in? 
                                        // Now we need a means to check that!
}

理想的にfooは、オブジェクトが「初期化」または有効化されていることを心配する必要はありません。

于 2013-03-22T07:17:23.967 に答える