3

Stroustrupのよくある質問の 1 つで、彼は次の例を挙げています。

template<class Scalar> class complex {
public:
    complex() : re(0), im(0) { }
    complex(Scalar r) : re(r), im(0) { }
    complex(Scalar r, Scalar i) : re(r), im(i) { }
    // ...

    complex& operator+=(const complex& a)
        { re+=a.re; im+=a.im; return *this; }
    // ...
private:
    Scalar re, im;
};

次のように説明します。

この型は組み込み型と同じように使用するように設計されており、真にローカルオブジェクト(つまり、ヒープではなくスタックに割り当てられるオブジェクト)を作成できるようにするために宣言で表現が必要です。単純な操作のインライン化

誰かがこれを説明してくれますか? Put reimクラス宣言のデータにより、クラスオブジェクトがスタックに割り当てられますか? そして、インライン化はどうですか?operator+=(インライン化されているのが見えますが、彼はこれを意味しているのでしょうか?)

4

3 に答える 3

3

これは、派生することを意図していない具象クラスです (必要がないため)。

おそらく、複素数のインターフェイスを定義したり、さまざまな種類の複素数 (それが何であれ) を導出したり、それらを多態的に使用したりしたくないでしょう。

クラスにすべてを含めることにより、コンパイラは、抽象インターフェイスと仮想関数を使用する場合よりも、おそらくこれを簡単に最適化できます。

ここに魔法はないと思います。これは、「値型」クラスの使用が適切な場所の例にすぎません。

于 2012-09-14T07:25:44.363 に答える
3

メンバーreimは、すべてのcomplexオブジェクト内に割り当てられます。つまり、オブジェクト全体がスタックに割り当てられている場合にのみ、 とreがスタックに割り当てられます。オブジェクトがグローバルの場合、とはスタックにもヒープにもありません。imcomplexcomplexreim

実際には、コンパイラはオブジェクトのオフセットre0 とオフセットに置きます。これは、 のコードがそれらのメンバーを取得するために多くのアセンブリ命令を必要としないことを意味します。実際の追加自体はおそらく 2 つのアセンブリ命令にすぎないため、4 つのメンバーをロードして 2 つの結果を格納する作業は作業の大部分を占めます。インライン化は、インライン化するものがほとんどない場合に最適です。imsizeof(Scalar)operator+=

于 2012-09-14T07:26:15.413 に答える
1

クラス定義にデータを入れても、オブジェクトはスタックに割り当てられませんが、許可されます。オブジェクトが定義された時点で、コンパイラはその完全なサイズを認識している必要があります。オブジェクトがスタック上で定義される場合、コンパイラはそれを定義する変換単位でのサイズを認識している必要があります。

クラス定義にデータを配置しないということは、データを他の場所に割り当てるためにいくつかの手順を実行する必要があることを意味し、他の場所ではほぼ確実に動的割り当てが必要になります。

同様に、インライン関数は、表示されるデータのみを操作できます。

クラスでデータ宣言を回避するためのさまざまなスキーマがあります。特にデータ型が複雑でユーザー定義の場合は、重要な利点があります。それらはすべて動的割り当てを伴います。Stroustrup が言っていることは、小さな具体的なクラスの場合、クラスにデータを配置することで、組み込み型のように動作 (および実行) でき、動的な割り当てがなく、多くの場合 (インライン化のため) 抽象化のペナルティがないということです。

于 2012-09-14T07:57:32.663 に答える