2011-09-19 99 views
3

試圖研究C++函數模板。作爲其中的一部分,我有下面的代碼。它工作正常,但我有如下問題: -關於重載運算符的問題<<

1]爲什麼運營商< <重載功能需要的朋友?如果我刪除關鍵字朋友,它會給編譯錯誤說:操作員< <有太多的參數。

2]爲什麼運算符重載函數需要返回一個對它的輸入參數的ostream對象的引用呢?

3]我懷疑這個,但是上面的兩個問題是否與事實有關:函數模板用於已經重載函數的用戶定義的類的事實?

template <class T> 
T Average(T *atArray, int nNumValues) 
{ 
    T tSum = 0; 
    for (int nCount=0; nCount < nNumValues; nCount++) 
     tSum += atArray[nCount]; 

    tSum /= nNumValues; 
    return tSum; 
} 

class Cents 
{ 
private: 
    int m_nCents; 
public: 
    Cents(int nCents) 
     : m_nCents(nCents) 
    { 
    } 

    //Why is friend needed below 

    //Why does it need to return ostream&, why can't it have void return type, as all it is doing is printing the class private member. 
    friend ostream& operator<< (ostream &out, const Cents &cCents) 
    { 
     out << cCents.m_nCents << " cents "; 
     return out; 
    } 

    /* 
    void operator <<(const Cents &cCents) //did not work - compilation errors 
    { 
     cout << cCents.m_nCents << " cents "; 
    } 
    */ 

    void operator+=(Cents cCents) 
    { 
     m_nCents += cCents.m_nCents; 
    } 

    void operator/=(int nValue) 
    { 
     m_nCents /= nValue; 
    } 
}; 

int main() 
{ 
    int anArray[] = { 5, 3, 2, 1, 4 }; 
    cout << Average(anArray, 5) << endl; 

    double dnArray[] = { 3.12, 3.45, 9.23, 6.34 }; 
    cout << Average(dnArray, 4) << endl; 

    Cents cArray[] = { Cents(5), Cents(10), Cents(15), Cents(14) }; 
    cout << Average(cArray, 4) << endl; 

    cin.get(); 
    return 0; 
} 

回答

3

爲什麼運營商< <需要重載功能的朋友?如果我刪除關鍵字朋友,它會給編譯錯誤說:操作員< <有太多的參數。

<<改變了流的狀態,因此理想情況下它應該被實現爲左操作數類型的成員。然而,其左邊的操作數是來自標準庫的流,雖然標準庫定義的大部分流輸出和輸入操作符都確實定義爲流類的成員,但是當您爲自己的類型實現輸出和輸入操作時,不能更改標準庫的流類型。
這就是爲什麼您需要爲您自己的類型實現這些(<<>>)運算符作爲非成員函數的原因。由於您需要在運算符定義中訪問類對象的私有/受保護成員變量,因此需要將這些重載運算符聲明爲您的類的朋友。

爲什麼運算符重載函數需要返回一個對ostream對象的引用,這也是它的輸入參數?

返回到標準的流對象的引用允許你有對象鏈接

您可以像電話:

out<<obj1<<obj2; 

模板用於已重載函數用戶定義的類?

模板幫你實現通用的函數和類可以要求不同的數據類型 和編譯器生成的代碼,這些具體的數據類型的護理。所以上述兩點是沒有關係的。


強烈建議閱讀此FAQ條目:
Operator overloading

+0

感謝。我有一個疑問,就是爲什麼不能做一個類成員函數。因爲最後這就是我要使用operator << with,用戶定義的類的對象,不是它。爲什麼它需要成爲非會員/一般功能? – goldenmean

+0

@goldenmean:我的答案的第一部分涉及到這一點,您應該通讀我添加到答案中的鏈接,以幫助您更好地理解這一點,並解決您的疑問。 –

0

它必須返回一個ostream,並採取一個作爲參數,所以你可以將多個電話一起。

如:

Cents a,b,c; 
cout << a << b << c; 

它必須是一個朋友,因爲它不是一個成員函數,不管你的代碼class塊中定義的事實。

讓我擴展這個概念。上面的示例等效於以下內容:

op(op(op(cout,a),b),c); 

其中'op'是重載運算符的實際函數名稱的簡寫。請注意,它不是在Cents實例上調用的,實際上沒有this ptr,因爲它存在於類之外,就像獨立函數一樣。

1

[1]它需要是朋友,因爲它試圖訪問私有成員變量m_nCents,只有成員函數CentsCents的朋友才能訪問。

[2]這是用於重載「流媒體運算符」的標準函數簽名。這使得有可能以連接<< S:

out << a << b; 

這相當於

(out << a) << b; 

編輯:看來你想要的operator<<是類的成員。這是不可能的,因爲它的第一個操作數是ostream而不是Centsfriend實際上聲明它是一個非成員的朋友函數。如果您將friend關鍵字放在遠處,則將其聲明爲成員函數(因爲它位於類定義內),但在這種情況下,它具有太多參數(簽名中的兩個參數和隱含的Cents作爲第一個參數,它是如果你喜歡,請撥打this指針)。

聲明的operator<<流媒體作爲一個非成員函數是做它的標準方式,無論是friend與否(取決於你的情況,你需要friend,或者你讓m_nCents公開可用不知)。