2012-09-14 58 views
3

one of Stroustrup's faq question,他給出了下面的例子:將數據放在類聲明中?

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; 
}; 

,並介紹:

這種類型的設計是使用多爲內置型和需要在聲明中表示,使它可能創建真正的本地對象(即分配在堆棧上而不是堆上的對象)並確保正確內聯簡單操作

有人可以幫忙解釋一下嗎?把re,im中的數據放在類聲明中讓類對象在棧上分配?內聯怎麼樣? (我可以看到一個內嵌的operator+=,這是他的意思嗎?)

+0

我已經刪除了第二個問題。隨意再次提問,但如果您這樣做,請提供您想知道的源代碼。 – MSalters

+0

你有沒有把「複雜」稱爲「基類」的原因?它使問題標題產生誤導。 – juanchopanza

+0

謝謝juanchopanza。更正它。 – user1559625

回答

1

把數據類定義不會使對象 在棧上分配,但它允許它。在定義對象 的地方,編譯器必須知道它的完整大小;如果在堆棧中定義了對象 ,則編譯器必須在定義它的翻譯單元中知道其大小。

不把數據類定義意味着你必須採取 一些步驟,以在其他地方分配數據,以及其他地方將 幾乎肯定會涉及到動態分配。

同樣,內聯函數只能操縱它所看到的數據。

有避免類中的數據聲明的各種模式。 它們可以具有重要的優勢,特別是在數據類型爲 複雜和用戶定義的情況下。它們都涉及動態分配。什麼 Stroustrup說,對於小的具體類,將類中的數據 允許它們像內置的 類型一樣運行(並執行),而沒有動態分配,並且通常(因爲內聯)沒有 抽象罰款。

+0

謝謝詹姆斯。寫得好,有道理。 – user1559625

3

這是一個不打算從(因爲沒有必要)派生的具體類。

你可能不希望定義一個接口,用於複數,並從中獲得不同種類的複數(不管這將是)和多態地使用它們。

通過擁有類中的所有內容,與使用抽象接口和虛函數相比,編譯器可能更容易對其進行優化。

我不認爲這有什麼神奇在這裏,它只是在那裏用「價值型」級是合適的例子。

+0

謝謝博。當我閱讀Stroustrup的一些常見問題時,我有時會以他解釋的方式感到困惑。經常試圖確定我確實不會錯過主要觀點。 – user1559625

3

成員reim被分配在每個complex對象內。這意味着reim被分配在堆棧當且僅當整個complex對象是。如果complex對象是全局對象,則reim既不在堆棧中,也不在堆上。

實際上,編譯器會將re放置在對象中的偏移量爲0,im的偏移量爲sizeof(Scalar)。這意味着operator+=的代碼不需要大量的彙編指令來獲取這些成員。實際的添加本身可能只是兩個彙編指令,因此加載4個成員並存儲這兩個結果是該工作的主要部分。如果內聯很少,並且內聯的效果最好。