簡體   English   中英

std :: ostream需要函數幫助

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM