2013-08-03 85 views
9

爲什麼我不能像這樣爲什麼std :: ostream的構造函數受到保護?

std::ostream out; 

我的輸出創建一個「空」流?

此行是根據與libstdc++ Linux的clang 3.4gcc 4.8.1顯然是非法的,我真的不知道爲什麼,我的意思是,爲什麼我不能只是出於創建流無處並使用它就像我想?請注意,std::ofstream out;是100%確定。我只是不明白這背後的邏輯。 如果你認爲創建後我可以使用這個緩衝區,並與其他緩衝區共享一個公共緩衝區與copyfmt,這是更奇怪,所以沒有真正的需要我的std::ostream被初始化爲從創建對象到有用。

請不要偏離這個,我不需要stringstreams,我需要ios流,因爲我必須做的,因爲他們提供的方法和屬性。

+1

你期待'ostream'做什麼? – Rapptz

+1

@Rapptz表現得像'std :: cout'或'std :: cerr'?就像輸出流一樣? – user2485710

+0

我認爲他的意思是「輸出到哪裏」。順便說一句 - cout和cerr輸出到不同的位置。他們恰好是默認情況下打印到屏幕 – rabensky

回答

11

我承認,我也不明白。我找不到任何 默認的構造函數在所有的std::istream,我會覺得 你想一個,如果你想要的,因爲奇怪的方式std::ios_base作品打造的雙向流, :在 構造函數任何初始化,但派生的 類必須在其構造函數 中明確調用std::ios_base::init。當涉及多繼承時(即 雙向IO,其中類來自 std::istreamstd::ostream),我期望只有最多的 派生類才能調用std::ios_base::init。 (在 std::iostreamstd::ios_base::init會被調用兩次。) 事實上,在標準查找它之前,我正要 答案是默認的構造函數是受保護的,因爲它 沒有叫std::ios_base::init,並直接使用它,而不是派生類中的 ,則會導致未初始化的 流。

總之,你的直接問題有一個簡單的解決方案:

std::ostream out(NULL); 

另外:你以後需要設立水槽的功能是rdbuf()的 非const版本,而不是copyfmt()rdbuf()是用於讀取和指針設置爲streambufcopyfmt()複製格式化標誌 ,但並沒有觸摸的 指針streambuf

所以你可以做這樣的事情:

std::ostream out(NULL); 
// ... 
std::filebuf fileBuffer; 
if (filenameGiven) { 
    fileBuffer.open(filename.c_str(), std::ios_base::out); 
} 
if (fileIsOpen()) { 
    out.rdbuf(&fileBuffer); 
} else { 
    out.rdbuf(std::cout.rdbuf()); 
} 

(我這樣做了很多其實,我認爲這是通常的 成語的時候,你不知道前面是否輸出到文件 或std::cout

編輯:

而且又修正:的rdbuf電話clear()非const版本, 所以你不必。(我知道我這樣做沒有調用clear(),但 當我看到init設置badbit ...)

總之:總結是:它通常preferrable將指針傳遞到有效 streambuf來構造的std::ostream,但如果你不能,它是 完全有效的通過一個空指針,並設置一個有效的指針後使用 rdbuf()。而其他答案都是錯誤的。

+1

終於:D。men標準庫的ios部分是程序員的真實旅程...... – user2485710

+0

有趣的初始化舞蹈發生在'std :: ios'和'std :: istream之間'/'std :: ostream' /'std :: iostream':用戶不必處理它,除非他們想直接從'std :: ios'派生!跳舞的原因是爲了避免流在構建'std :: iostream'時緩衝區被設置兩次:'std :: ios :: init()'只是從該類的默認構造函數調用。 ...這實際上也是std :: ostream被保護的默認構造的原因:它不會觸及'std :: ios'中的流緩衝區,並使其未初始化! –

+0

@ user2485710它實際上比標準庫的其餘部分簡單得多。從用戶的角度來看,當然這很複雜,因爲它的工作非常複雜。 –

2

stringstreamios流。

但是關於你的問題:

ostream某處寫道。如果您聲明

std::ostream out; 
out << "Hello, world!"<<std::endl 

"Hello, world!"應寫在某處。但是哪裏?這取決於每個具體的ostream的實施。是的,有一個緩衝區,但該緩衝區還取決於具體的實現。

所以,當你說「我想要一個ostream」我必須問 - 一個寫東西......到哪裏?

給出你的答案,這將告訴我你需要使用哪個具體的實例/實現ostream

+0

那麼,如果我寫'int a;'我不必聲明存儲int的位置,編譯器會爲我做,爲什麼一個流不能有一個「默認」的「後備」值,仍然在有效狀態? – user2485710

+0

因爲它必須在某處打印!它將在哪裏打印?如果存在默認設置,那將是「我不知道要打印到哪裏,所以我只會扔掉你寫的所有東西」。這相當於你的'int'例子(如果你只能寫入'int'而不是從它讀取,就像'ostream')。但是這種行爲會很愚蠢,很可能不是你想要的。只要告訴我們你在寫東西時想要實際發生什麼,以及爲什麼cout不夠好 – rabensky

+0

場景:我有一個用C++編寫的程序,它還提供了一種腳本語言的包裝,我需要存儲和輸出(有一個緩衝區基本上)關於應用程序的狀態,錯誤和調試消息,但我想保留這3個緩衝區爲C++應用程序和腳本封裝器分開,所以我需要總共6個緩衝區,我不想他們混合在一起,我希望他們永遠不會看到一個到另一個,我想決定什麼輸出我可以重定向這6個流:你選擇什麼類或類型? – user2485710

8

std::ostream在概念上是抽象的 - 你不應該創建它們(但看到更多細節的其他答案)。

std::stringstream給你的一切std::ostream確實是因爲它來自它。這也意味着,在任何你想要std::ostream&的地方,例如在函數參數中,你可以傳遞一個std::stringstream對象。

你說「沒有必要初始化它」。這根本沒有意義。你不能使用沒有初始化的任何東西:甚至int s。

+0

我忘了指定從我的角度來看,初始化到用戶給定的特定值或狀態可能是無用的,這就是我的意思,但無論如何,我可以在哪裏找到ostream的層次結構? – user2485710

+0

請看這個http:// stackoverflow。com/questions/18031357/stdostream-is-protected的構造函數#comment26376038_18031398 – user2485710

+0

'std :: ostream'根本不抽象!它甚至沒有任何「虛擬」功能,除了它的析構函數。你可以通過使用帶'std :: streambuf *'的構造函數來創建'std :: ostream'。 –

2

std :: ostream是一個廣義的流類。因爲它沒有辦法知道它流到哪裏,這是具有廣義類的全部意義。

將數據發送到流時,它實際上並不存儲數據本身。它只是將它傳遞給關聯的緩衝區。考慮到這一點,創建一個廣義流而不分配這個緩衝區是沒有意義的,因爲廣義類不能創建一個空的廣義緩衝區。(緩衝區本身需要是一個具體類型的緩衝區,這也可以通過查看根本沒有公共控制器的廣義緩衝區std :: treambuf來理解)

將此與std :: ofstream是具有特定類型緩衝區的流,現在可以讓ofstream知道它使用的緩衝區類型,從而能夠實例化默認的std :: filebuf。

解決您的具體問題。

首先創建你想要的類型的緩衝區,然後創建一個廣義的std :: ostream,緩衝區作爲參數。然後您可以稍後使用std :: filebuf :: open()連接到一個文件。

例子:

std::filebuf fileBuffer; 
std::ostream myOstream(&fileBuffer); // Hand over the address of the fileBuffer 

fileBuffer.open("filename.txt", std::ios::out); 
myOstream << "Text to file"; 
+0

他的整個觀點是他沒有'streambuf '直到後來,所以他不能這樣做,這可能是一個有問題的架構;'streambuf'通常需要一個至少與'istream'相同的生命週期,所以人們會期望它被首先創建,但是 –

4

默認構造的std::basic_ostreamprotected,因爲它通常沒有任何意義,沒有設置創建std::basic_ostreamstd::basic_streambuf和默認構造函數實際上沒有做任何初始化(見下文)。但是,另一個構造函數將流緩衝區作爲參數。如果你真的需要這是不成立做任何事情,但一個std::ostream,您可以使用該構造:

std::ostream out(0); 

,直到流緩衝區設置使用std::ios::rdbuf()std::ostream將有std::ios_base::badbit集。

std::ostream的默認構造函數爲protected的根本原因是它實際上故意沒有做任何有用的事情!特別是,調用這個構造函數[來自另一個派生類]將根本不會初始化流緩衝區:而不是;標準沒有明確地強制任何行爲,即默認的構造函數隱式地具有生成默認構造函數的行爲(或,在C++ 2011中就好像它是使用= default定義的)。要初始化流緩衝區,它需要調用std::ios::init()。造成這種奇怪行爲的原因是構造進一步派生類std::iostream的對象會將對象初始化兩次,一次通過std::ostream,一次通過std::istream

與其他一些答案建議不同,std::ostream根本不抽象。事實上,無論如何它只有一個virtual函數,那就是它的析構函數(析構函數是virtual恰好是我的錯,我不完全相信這是強制執行的好主意)。

+0

我覺得你誤解了一些東西。說「默認構造函數是_abstract_」是什麼意思?函數不是抽象的,類是的,構造函數也不是虛擬的。默認的構造函數根本就不存在(因爲還有其他構造函數,編譯器也不會生成它)。 –

+0

@JamesKanze:好點。我的意思是寫*保護*(稍後會糾正)。謝謝! –

+0

你的帖子正是我的想法,直到我在標準中查找它。有_is_沒有默認構造函數,至少我可以找到。你描述的內容比標準內容更有意義(這也是我的想法,直到我看到它),但似乎並非如此。 (也許這是經典的,預標準的IO流的情況,我們都在想這個。) –

相關問題