如果執行IO操作符時需要存取對象的私有成員,通常有以下兩種方法:
使用輔助函數
IO操作符應該將實際任務委派給輔助的成員函數。這種技術允許具有多態性,如下:
class Fraction
{
public:
Fraction( int nNumerator = 0, int nDemominator = 1 )
:m_nNumerator( nNumerator ), m_nDemominator( nDemominator )
{}
//輔助輸入輸出函數
virtual void PrintOn( std::ostream& strm ) const
{
strm << m_nNumerator << '/' << m_nDemominator;
}
virtual void ScanFrom( std::istream& strm )
{
strm >> m_nNumerator;
strm.ignore(); //ignore '/'
strm >> m_nDemominator;
}
private:
int m_nNumerator; //分子
int m_nDemominator; //分母
};
std::ostream& operator << ( std::ostream& os, const Fraction& f )
{
f.PrintOn( os );
return os;
}
std::istream& operator >> ( std::istream& in, Fraction& f )
{
f.ScanFrom( in );
return in;
}
設置IO操作爲類的友元函數
訪問類的私有成員,也可以將IO操作符函數設計爲類的友元函數
class Fraction
{
friend std::ostream& operator << ( std::ostream&, const Fraction&);
friend std::istream& operator >> ( std::istream&, Fraction& );
public:
Fraction( int nNumerator = 0, int nDemominator = 1 )
:m_nNumerator( nNumerator ), m_nDemominator( nDemominator )
{}
private:
int m_nNumerator; //分子
int m_nDemominator; //分母
};
std::ostream& operator << ( std::ostream& os, const Fraction& f )
{
os << f.m_nNumerator << '/' << f.m_nDemominator;
return os;
}
std::istream& operator >> ( std::istream& in, Fraction& f )
{
in >> f.m_nNumerator;
in.ignore(); //ignore '/'
in >> f.m_nDemominator;
return in;
}
對比
如果你的類不會作爲其他類的基類,以上兩種方法都一樣。
否則的話,一旦用上繼承,使用friend的方法就有很大的侷限性。friend函數不能成爲虛函數,所以程序可能會調用錯誤的函數。例如,某個基類引用實際指向一個派生類引用,並補當作input操作符的參數,則被調用的將是基類的操作符。爲了避免出現這種情況,繼承類不得實作自己的IO操作符,並且還要顯示調用(因爲不是虛函數)。
因此,使用第一種方法通用的多,儘管你在其它文件或書籍上看到的絕大多數例子使用的是friend函數,你最好將第一種方法視爲標準作法。