[英]std::ostream need help with function
我需要有人一個一個地向我解釋這些代碼行,我需要幫助使用“ostream”和簡單的例子。 謝謝 :)。
inline std::ostream& operator<<(std::ostream& os, const Telegram& t)
{
os << "time: " << t.DispatchTime << " Sender: " << t.Sender
<< " Receiver: " << t.Receiver << " Msg: " << t.Msg;
return os;
}
更新1:當我使用此功能時,它不會編譯,錯誤說:
std :: ostream&class :: operator <<(std :: ostream&os,const Telegram&t)必須只有一個參數
這些行只是添加了將Telegram對象處理為標准輸出流類的功能。
當您添加一個新類並且希望輸出流(如cout
智能地處理它們時,您需要添加一個新的<<
operator方法,該方法將新對象類型作為第二個參數。
上面的代碼正是這樣做的。 稍后執行語句時:
Telegram tg("Bob", "Hello, how are you?");
cout << tg;
將使用stream作為第一個參數並將tg
對象作為第二個參數調用您的問題中的函數,然后它將能夠以適合該類的格式輸出數據。
這實際上是我無法理解的早期C ++事情之一。 盡管該類應該是自包含的,但實際上是在向不同的類添加一些東西來處理輸出。 一旦你理解了為什么會這樣(因為它是負責輸出事物而不是你自己的類的ostream
類),它將有希望有意義。
希望通過一個更簡單的例子使其更清晰:
1 inline std::ostream& operator<<(std::ostream& os, const Telegram& t) {
2 os << "message: " << t.Msg;
3 return os;
4 }
第1行只是函數定義。 它允許您返回流本身(您傳入),以便您可以鏈接<<
段。 operator<<
只是你提供的函數,當你將<< tg
放入輸出流語句時調用它。
第2行使用更基本的<<
語句已經定義(在這種情況下,Msg類型,可能是一個字符串)。
然后第3行返回流,再次允許鏈接<<
segment。
其基本思路是,以提供operator<<
功能是建立在現有的operator<<
函數構成你的類型的數據類型。
並且使用一個只包含int
的簡單包裝類:
#include <iostream>
// This is my simple class.
class intWrapper {
public:
intWrapper (int x) { myInt = x; };
int getInt (void) { return myInt; }
private:
int myInt;
// Must be friend to access private members.
friend std::ostream& operator<< (std::ostream&, const intWrapper&);
};
// The actual output function.
inline std::ostream& operator<< (std::ostream& os, const intWrapper& t) {
os << "int: " << t.myInt;
return os;
}
// Main program for testing.
// Output with getter and with ostream.
int main (void) {
class intWrapper x(7);
std::cout << x.getInt() << std::endl; // ostream already knows about int.
std::cout << x << std::endl; // And also intWrapper, due to the
// function declared above.
return 0;
}
這輸出:
7
int: 7
第一個是通過調用getter函數來檢索整數,第二個是通過調用我們添加到ostream
的<<
operator函數。
您發布的函數(以下稱“函數”)是插入運算operator <<
的重載。 它允許您將Telegram
類型的對象或從Telegram
派生或可轉換為Telegram
任何其他類型的對象輸出到輸出流。 這與C ++中IO流的常見用法類似:
std::cout << 0 << '\n';
在這里輸出int
0,然后輸出char
newline到標准輸出流。 使用您發布的功能,您現在可以執行類似的操作
Telegram tel; // if Telegram has a default constructor
std::cout << tel << '\n';
您可能無法做到的事情,因為標准C ++庫不知道您的新Telegram
類型,因此從未定義如何輸出此類對象。
在代碼中:
inline std::ostream& operator<<(std::ostream& os, const Telegram& t)
第一行以inline
關鍵字開頭。 據推測,該函數是在頭文件中定義的,因此在這種情況下,您必須使用inline
關鍵字,以便定義不違反一個定義規則。
也就是說,每次在實現文件中包含標頭時,都會獲得為該實現文件定義的函數。 當鏈接器將所有編譯的目標文件鏈接在一起時,它將找到該函數的多個定義,每個實現文件中有一個定義包含您發布的函數的標題。 這是C ++禁止的; C ++要求一個函數可以實現不超過一次,如果你打算調用它,恰好一次。
使用inline
關鍵字本質上要求C ++編譯器確保函數不會被定義多次,以致鏈接器跳出其位置並抱怨可供選擇的多個定義的模糊性。
在這里,我認為內聯函數是一個壞主意。 最好刪除inline
關鍵字並將函數定義移動到自己的轉換單元或實現文件中。 這樣,函數將只編譯一次,而不是每個包含帶函數頭的實現文件一次。
接下來您將注意到函數是一個自由函數,而不是成員函數。 這允許(實際上需要)函數來指定操作符的左操作數,即流對象。 這意味着該函數將適用於任何可轉換為流的對象。 它還意味着您不需要修改類以將此擴展添加到輸出語義。 如果函數是成員,那么您必須更改類的標題,這反過來意味着重新編譯包含該標題的所有實現文件。 當然,看起來您的功能是在標題中定義的; 如上所述,這可能是一個壞主意。
接下來,您會看到該函數返回一個std::ostream
。 std::ostream
實際上是以std::basic_ostream<char, std::char_traits<char> >
,因此你的函數只能將Telegram
對象輸出到處理char
類型的流。
函數返回std::ostream
的原因是您可以鏈接對函數的調用。 如果你仔細看,
std::cout << 0 << 1;
實際上是對插入運算符重載函數的兩個調用鏈。 一旦輸出0,然后輸出1.它相當於
std::operator<<(std::operator<<(std::cout, 0), 1);
第一次調用insert 0返回一個輸出流,第二次調用insert 1獲取返回的輸出流並插入到1.這就是我們返回輸出流的原因:所以我們可以鏈接調用。
您還將注意到插入運算符具有從左到右的關聯性,這意味着在上面的語句中,0保證首先輸出,1秒。 這與我上面寫的等效行相反,其中關聯性(函數調用)是由內而外的。 這產生了一個更不易讀的代碼IMO,這是使用operator <<
作為輸出語義的好處之一。
接下來看一下函數的參數。 第一個參數是std::ostream
,它是通過引用獲得的。 這樣您就可以更改流。 這也是const
引用不采用流的原因。
第二個參數可以由const
引用獲取,因為我們不想更改它,只需讀取它。 但是,我們確實希望通過引用來接受它,因為我們不打算改變它,甚至不是為了本地目的,因此保存副本的構造只是一個好主意。 如果需要,它還允許接受Telegram
衍生產品並在其上加密虛擬功能。 另外,使用const
引用允許您輸出臨時值,如std::cout << Telegram() << '\\n';
。
{
os << "time: " << t.DispatchTime << " Sender: " << t.Sender
<< " Receiver: " << t.Receiver << " Msg: " << t.Msg;
這段代碼現在應該是自我解釋的。 據推測,您插入到輸出流中的每個成員都具有為其定義的插入運算符。 標准庫定義插入到基元,字符串,復數和其他標准類型的輸出流。
return os;
}
最后返回流對象,這樣調用者就可以輸出另一個對象來鏈接輸出。 請注意,您只需返回鏈的結果:
return os << "time: " << t.DispatchTime << " Sender: " << t.Sender
<< " Receiver: " << t.Receiver << " Msg: " << t.Msg;
最后,為了演示使用免費函數獲得的獎金並通過引用獲取Telegram
參數,請考慮:
struct Telegram {
Telegram();
Telegram(const Communication& c);
virtual ~Telegram();
};
struct Message : public Telegram {
};
struct Letter {
operator Telegram() const;
};
// ...
Telegram t;
Communication c;
Message m;
Letter l;
std::cout << t << '\n'
<< c << '\n'
<< m << '\n'
<< l << '\n';
全部使用該單個函數輸出Telegram
對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.