?[轉]
C++的iostream標準庫介紹
0 為什么需要iostream
我們從一開始就一直在利用C++的輸入輸出在做著各種練習,輸入輸出是由iostream庫提供的,所以討論此標準庫是有必要的,它與C語言的 stdio庫不同,它從一開始就是用多重繼承與虛擬繼承實現的面向對象的層次結構,作為一個c++的標準庫組件提供給程序員使用。
iostream為內置類型對象提供了輸入輸出支持,同時也支持文件的輸入輸出,類的設計者可以通過對iostream庫的擴展,來支持自定義類型的輸入輸出操作。
為什么說要擴展才能提供支持呢?我們來一個示例。
#include <stdio.h>
#include <iostream>
usingnamespace std;
class Test
{
public:
Test(int a=0,int b=0)
{
Test::a=a;
Test::b=b;
}
int a;
int b;
};
int main()
{
Test t(100,50);
printf("%???",t);//不明確的輸出格式
scanf("%???",t);//不明確的輸入格式
cout<<t<<endl;//同樣不夠明確
cin>>t;//同樣不夠明確
system("pause");
}
? 由于自定義類的特殊性,在上面的代碼中,無論你使用c風格的輸入輸出,或者
是c++的輸入輸出都不是不明確的一個表示,由于c語言沒有運算符重載機制,導致
stdio庫的不可擴充性,讓我們無法讓printf()和scanf()支持對自定義類對象的
擴充識別,而c++是可以通過運算符重載機制擴充 iostream庫的,使系統能能夠識
別自定義類型,從而讓輸入輸出明確的知道他們該干什么,格式是什么。
在上例中我們之所以用printf與cout進行對比目的是為了告訴大家,C與C++處理輸入輸出的根本不同,我們從c遠的輸入輸出可以很明顯看出是函數調用方式,而c++的則是對象模式,cout和cin是ostream類和istream類的對象。
1 iostream: istream 和 ostream
C++中的iostream庫主要包含下圖所示的幾個頭文件:
IOSstream 庫
|
fstream
|
iomainip
|
ios
|
iosfwd
|
iostream
|
istream
|
ostream
|
sstream
|
streambuf
|
strstream
|
我們所熟悉的輸入輸出操作分別是由istream(輸入流)和ostream(輸出流)這兩個類提供的,為了允許雙向的輸入/輸出,由istream和ostream派生出了iostream類。
類的繼承關系見下圖:
iostream庫定義了以下三個標準流對象:
-
cin,表示標準輸入(standard input)的istream類對象。cin使我們可以從設備讀入數據。
-
cout,表示標準輸出(standard output)的ostream類對象。cout使我們可以向設備輸出或者寫數據。
-
cerr,表示標準錯誤(standard error)的osttream類對象。cerr是導出程序錯誤消息的地方,它只能允許向屏幕設備寫數據。
輸出主要由重載的左移操作符(<<)來完成,輸入主要由重載的右移操作符(>>)完成:
-
>>a表示將數據放入a對象中。
-
<<a表示將a對象中存儲的數據拿出。
這些標準的流對象都有默認的所對應的設備,見下表:
?
C++對象名
|
設備名稱
|
C中標準設備名
|
默認含義
|
cin
|
鍵盤
|
stdin
|
標準輸入
|
cout
|
顯示器屏幕
|
stdout
|
標準輸出
|
cerr
|
顯示器屏幕
|
stderr
|
標準錯誤輸出
|
上表中的意思表明cin對象的默認輸入設備是鍵盤,cout對象的默認輸出設備是顯示器屏幕。
那么原理上C++有是如何利用cin/cout對象與左移和右移運算符重載來實現輸入輸出的呢?
下面我們以輸出為例,說明其實現原理:
-
cout是ostream類的對象,因為它所指向的是標準設備(顯示器屏幕),所以它在iostream頭文件中作為全局對象進行定義。
-
ostream cout(stdout);//其默認指向的C中的標準設備名,作為其構造函數的參數使用。
-
在iostream.h頭文件中,ostream類對應每個基本數據類型都有其友元函數對左移操作符進行了友元函數的重載。
-
ostream& operator<<(ostream &temp,int source);
-
ostream& operator<<(ostream &temp,char *ps);
-
... 等等
一句輸出語句:cout<<"http://www.shnenglu.com/andxie99";,事實上調用的就是ostream& operator<<(ostream &temp,char *ps);這個運算符重載函數,由于返回的是流對象的引用,引用可以作為左值使用,所以當程序中有類似cout<<"http://www.shnenglu.com/andxie99"<<"白紙人生";這樣的語句出現的時候,就能夠構成連續輸出。
由于iostream庫不光支持對象的輸入輸出,同時也支持文件流的輸入輸出,所以在詳細講解左移與右移運算符重載只前,我們有必要先對文件的輸入輸出以及輸入輸出的控制符有所了解。
2 fstream: ifstream 和 ofstream
和文件有關系的輸入輸出類主要在fstream.h這個頭文件中被定義,在這個頭文件中主要被定義了三個類,由這三個類控制對文件的各種輸入輸出操作,他們分別是ifstream、ofstream、fstream,其中fstream類是由iostream類派生而來,他們之間的繼承關系見下圖所示。
由于文件設備并不像顯示器屏幕與鍵盤那樣是標準默認設備,所以它在fstream.h頭文件中是沒有像cout那樣預先定義的全局對象,所以我們必須自己定義一個該類的對象,我們要以文件作為設備向文件輸出信息(也就是向文件寫數據),那么就應該使用ofstream類。
ofstream類的默認構造函數原形為:
ofstream::ofstream(constchar *filename,int mode = ios::out,int openprot = filebuf::openprot);
-
filename: 要打開的文件名
-
mode: 要打開文件的方式
-
prot: 打開文件的屬性
其中mode和openprot這兩個參數的可選項表見下表:
mode屬性表
|
ios::app
|
以追加的方式打開文件
|
ios::ate
|
文件打開后定位到文件尾,ios:app就包含有此屬性
|
ios::binary
|
以二進制方式打開文件,缺省的方式是文本方式。兩種方式的區別見前文
|
ios::in
|
文件以輸入方式打開
|
ios::out
|
文件以輸出方式打開
|
ios::trunc
|
如果文件存在,把文件長度設為0
|
可以用“或”把以上屬性連接起來,如ios::out|ios::binary。
openprot屬性表
|
屬性
|
含義
|
0
|
普通文件,打開訪問
|
1
|
只讀文件
|
2
|
隱含文件
|
4
|
系統文件
|
可以用“或”或者“+”把以上屬性連接起來 ,如3或1|2就是以只讀和隱含屬性打開文件。
實例代碼如下:
#include <fstream>
usingnamespace std;
int main()
{
ofstream myfile("c:\\1.txt",ios::out|ios::trunc,0);
myfile<<"白紙人生"<<endl<<"網址:"<<"www.shnenglu.com/andxie99";
myfile.close()
system("pause");
}
文件使用完后可以使用close成員函數關閉文件。
ios::app為追加模式,在使用追加模式的時候同時進行文件狀態的判斷是一個比較好的習慣。
示例如下:
#include <iostream>
#include <fstream>
usingnamespace std;
int main()
{
ofstream myfile("c:\\1.txt",ios::app,0);
if(!myfile)//或者寫成myfile.fail()
{
cout<<"文件打開失敗,目標文件狀態可能為只讀!";
system("pause");
exit(1);
}
myfile<<"白紙人生"<<endl<<"網址:"<<"www.shnenglu.com/andxie99"<<endl;
myfile.close();
}
在定義ifstream和ofstream類對象的時候,我們也可以不指定文件。以后可以
通過成員函數open()顯式的把一個文件連接到一個類對象上。
例如:
#include <iostream>
#include <fstream>
usingnamespace std;
int main()
{
ofstream myfile;
myfile.open("c:\\1.txt",ios::out|ios::app,0);
if(!myfile)//或者寫成myfile.fail()
{
cout<<"文件創建失敗,磁盤不可寫或者文件為只讀!";
system("pause");
exit(1);
}
myfile<<"白紙人生"<<endl<<"網址:"<<"www.shnenglu.com/andxie99"<<endl;
myfile.close();
}
下面我們來看一下是如何利用ifstream類對象,將文件中的數據讀取出來,然后再輸出到標準設備中的例子。
代碼如下:
#include <iostream>
#include <fstream>
#include <string>
usingnamespace std;
int main()
{
ifstream myfile;
myfile.open("c:\\1.txt",ios::in,0);
if(!myfile)
{
cout<<"文件讀錯誤";
system("pause");
exit(1);
}
char ch;
string content;
while(myfile.get(ch))
{
content+=ch;
cout.put(ch);//cout<<ch;這么寫也是可以的
}
myfile.close();
cout<<content;
system("pause");
}
上例中,我們利用成員函數get(),逐一的讀取文件中的有效字符,再利用put()成員函數,將文件中的數據通過循環逐一輸出到標準設備(屏幕)上, get()成員函數會在文件讀到默尾的時候返回假值,所以我們可以利用它的這個特性作為while循環的終止條件,我們同時也在上例中引入了C++風格的字符串類型string,在循環讀取的時候逐一保存到content中,要使用string類型,必須包含string.h的頭文件。
我們在簡單介紹過ofstream類和ifstream類后,我們再來看一下fstream類,fstream類是由iostream派生而來,fstream類對象可以同對文件進行讀寫操作。
示例代碼如下:
#include <iostream>
#include <fstream>
usingnamespace std;
int main()
{
fstream myfile;
myfile.open("c:\\1.txt",ios::out|ios::app,0);
if(!myfile)
{
cout<<"文件寫錯誤,文件屬性可能為只讀!"<<endl;
system("pause");
exit(1);
}
myfile<<"白紙人生"<<endl<<"網址:"<<"www.shnenglu.com/andxie99"<<endl;
myfile.close();
myfile.open("c:\\1.txt",ios::in,0);
if(!myfile)
{
cout<<"文件讀錯誤,文件可能丟失!"<<endl;
system("pause");
exit(1);
}
char ch;
while(myfile.get(ch))
{
cout.put(ch);
}
myfile.close();
system("pause");
}
由于fstream類可以對文件同時進行讀寫操作,所以對它的對象進行初始話的時候一定要顯式的指定mode和openprot參數。
接下來我們來學習一下串流類的基礎知識,什么叫串流類?
3 strstream: ostrstream 和 istrstream
簡單的理解就是能夠控制字符串類型對象進行輸入輸出的類,C++不光可以支持C++風格的字符串流控制,還可以支持C風格的字符串流控制。
我們先看看看C++是如何對C風格的字符串流進行控制的,C中的字符串其實也就是字符數組,字符數組內的數據在內存中的位置的排列是連續的,我們通常用 char str[size]或者char *str的方式聲明創建C風格字符數組,為了能讓字符數組作為設備并提供輸入輸出操作,C++引入了ostrstream、istrstream、 strstream這三個類,要使用他們創建對象就必須包含strstream.h頭文件。
-
istrstream類用于執行C風格的串流的輸入操作,也就是以字符串數組作為輸入設備。
-
ostrstream類用于執行C風格的串流的輸出操作,也就是一字符串數組作為輸出設備。
-
strstream類同時可以支持C風格的串流的輸入輸出操作。
istrstream類是從istream(輸入流類)和strstreambase(字符串流基類)派生而來,ostrstream是從 ostream(輸出流類)和strstreambase(字符串流基類)派生而來,strstream則是從iostream(輸入輸出流類)和和 strstreambase(字符串流基類)派生而來。
他們的繼承關系如下圖所示:
串流同樣不是標準設備,不會有預先定義好的全局對象,所以不能直接操作,需要通過構造函數創建對象。
類istrstream的構造函數原形如下:
istrstream::istrstream(constchar *str,int size);
?
參數1表示字符串數組,而參數2表示數組大小,當size為0時,表示istrstream類對象直接連接到由str所指向的內存空間并以\0結尾的字符串。
下面的示例代碼就是利用istrstream類創建類對象,制定流輸入設備為字符串數組,通過它向一個字符型對象輸入數據。代碼如下:
#include <iostream>
#include <strstream>
usingnamespace std;
int main()
{
char *name = "www.shnenglu.com/andxie99";
int arraysize = strlen(name)+1;
istrstream is(name,arraysize);
char temp;
is>>temp;
cout<<temp;
system("pause");
}
類ostrstream用于執行串流的輸出,它的構造函數如下所示:
ostrstream::ostrstream(char *_Ptr,int streamsize,int Mode = ios::out);
第一個參數是字符數組,第二個是說明數組的大小,第三個參數是指打開方式。
我們來一個示例代碼:
#include <iostream>
#include <strstream>
usingnamespace std;
int main()
{
int arraysize=1;
char *pbuffer=newchar[arraysize];
ostrstream ostr(pbuffer,arraysize,ios::out);
ostr<<arraysize<<ends;//使用ostrstream輸出到流對象的時候,要用ends結束字符串
cout<<pbuffer;
delete[] pbuffer;
system("pause");
}
上面的代碼中,我們創建一個c風格的串流輸出對象ostr,我們將arraysize內的數據成功的以字符串的形式輸出到了ostr對象所指向的pbuffer指針的堆空間中,pbuffer也正是我們要輸出的字符串數組,在結尾要使用ends結束字符串,如果不這么做就有溢出的危險。
4 stringstream
對于stringstream了來說,不用我多說,大家也已經知道它是用于C++風格的字符串的輸入輸出的。 stringstream的構造函數原形如下:
stringstream::stringstream(string str);
示例代碼如下:
#include <iostream>
#include <sstream>
#include <string>
usingnamespace std;
int main()
{
stringstream ostr("ccc");
ostr.put('d');
ostr.put('e');
ostr<<"fg";
string gstr = ostr.str();
cout<<gstr<<endl;
char a;
ostr>>a;
cout<<a
system("pause");
}
除此而外,stringstream類的對象我們還常用它進行string與各種內置類型數據之間的轉換。示例代碼如下:
#include <iostream>
#include <sstream>
#include <string>
usingnamespace std;
int main()
{
stringstream sstr;
//--------int轉string----------- int a=100;
string str;
sstr<<a;
sstr>>str;
cout<<str<<endl;
//--------string轉char[]--------
sstr.clear();//如果你想通過使用同一stringstream對象實現多種類型的轉換,請注意在每一次轉換之后都必須調用clear()成員函數。
string name = "colinguan";
char cname[200];
sstr<<name;
sstr>>cname;
cout<<cname;
system("pause");
}
接下來我們來學習一下輸入/輸出的狀態標志的相關知識.
5 io_state 輸入/輸出的狀態標志
C++中負責的輸入/輸出的系統包括了關于每一個輸入/輸出操作的結果的記錄信息。這些當前的狀態信息被包含在io_state類型的對象中。io_state是一個枚舉類型(就像open_mode一樣),以下便是它包含的值。
-
goodbit 無錯誤
-
Eofbit 已到達文件尾
-
failbit 非致命的輸入/輸出錯誤,可挽回
-
badbit 致命的輸入/輸出錯誤,無法挽回
有兩種方法可以獲得輸入/輸出的狀態信息。一種方法是通過調用rdstate()函數,它將返回當前狀態的錯誤標記。例如,假如沒有任何錯誤,則rdstate()會返回goodbit.下例示例,表示出了rdstate()的用法:
#include <iostream>
usingnamespace std;
int main()
{
int a;
cin>>a;
cout<<cin.rdstate()<<endl;
if(cin.rdstate() == ios::goodbit)
{
cout<<"輸入數據的類型正確,無錯誤!"<<endl;
}
if(cin.rdstate() == ios_base::failbit)
{
cout<<"輸入數據類型錯誤,非致命錯誤,可清除輸入緩沖區挽回!"<<endl;
}
system("pause");
}
另一種方法則是使用下面任何一個函數來檢測相應的輸入/輸出狀態:
bool bad();
bool eof();
bool fail();
bool good();
下例示例,表示出了上面各成員函數的用法:
#include <iostream>
usingnamespace std;
int main()
{
int a;
cin>>a;
cout<<cin.rdstate()<<endl;
if(cin.good())
{
cout<<"輸入數據的類型正確,無錯誤!"<<endl;
}
if(cin.fail())
{
cout<<"輸入數據類型錯誤,非致命錯誤,可清除輸入緩沖區挽回!"<<endl;
}
system("pause");
}
如果錯誤發生,那么流狀態既被標記為錯誤,你必須清除這些錯誤狀態,以使你的程序能正確適當地繼續運行。要清除錯誤狀態,需使用clear()函數。此函數帶一個參數,它是你將要設為當前狀態的標志值。,只要將ios::goodbit作為實參。
示例代碼如下:
#include <iostream>
usingnamespace std;
int main()
{
int a;
cin>>a;
cout<<cin.rdstate()<<endl;
cin.clear(ios::goodbit);
cout<<cin.rdstate()<<endl;
system("pause");
}
通常當我們發現輸入有錯又需要改正的時候,使用clear()更改標記為正確后,同時也需要使用get()成員函數清除輸入緩沖區,以達到重復輸入的目的。
示例代碼如下:
#include <iostream>
usingnamespace std;
int main()
{
int a;
while(1)
{
cin>>a;
if(!cin)//條件可改寫為cin.fail()
{
cout<<"輸入有錯!請重新輸入"<<endl;
cin.clear();
cin.get();
}
else
{
cout<<a;
break;
}
}
system("pause");
}
最后再給出一個對文件流錯誤標記處理的例子,鞏固學習,代碼如下:
#include <iostream>
#include <fstream>
usingnamespace std;
int main()
{
ifstream myfile("c:\\1.txt",ios_base::in,0);
if(myfile.fail())
{
cout<<"文件讀取失敗或指定文件不存在!"<<endl;
}
else
{
char ch;
while(myfile.get(ch))
{
cout<<ch;
}
if(myfile.eof())
{
cout<<"文件內容已經全部讀完"<<endl;
}
while(myfile.get(ch))
{
cout<<ch;
}
}
system("pause");
}
posted @
2006-06-29 20:30 Jerry Cat 閱讀(364) |
評論 (0) |
編輯 收藏
[轉自沐楓兄]用bitset進行2進制輸入輸出
C/C++內置的輸入、輸出,對整數進制只支持三種:8進制、10進制、16進制。記得很久以前,有好幾次想用到2進制的輸入輸出,最終只好自已轉換。
昨天kaikai突然發了一個POST:
kaikai:
看看能不能把這個程序改得更短
?
#include?
<
cstdio
>
int
?main()

{
????
char
*
a,b[
33
];
????scanf(
"
%*d
"
);
????
while
(scanf(
"
%s
"
,b)
==
1
)

????
{????
????????
int
?d
=
0
;
????????
for
(a
=
b;
*
a;)d
=
d
*
2
|*
a
++%
2
;
????????printf(
"
%d.%d.%d.%d\n
"
,d
>>
24
&
255
,d
>>
16
&
255
,d
>>
8
&
255
,d
&
255
);
????}
????
return
?
0
;
}
?
一眼看過去,呵呵,輸入輸出不可省,核心還是二進制的轉換問題。于是想起以前曾經做過的事情,學習多了,直覺的可以用bitset來實現。打開MSDN,查找bitset,嘿,果然有定義流輸入操作符。
寫了一個測試:
#include?
<
iostream
>
#include?
<
bitset
>
using
?
namespace
?std;

void
?main()

{
????bitset
<
32
>
?a;
????cin?
>>
?a;
????cout?
<<
?a.to_ulong()?
<<
?endl;????
}
呵呵,搞定了,輸入2進制,輸出10進制,完全正常。以后輸入2進制串的時候,就不需要自已轉換了。
posted @
2006-06-29 20:22 Jerry Cat 閱讀(364) |
評論 (0) |
編輯 收藏
1》誤會;2》釘子;3》且慢下手;4》寬大。
1》誤會:
早年在美國阿拉斯加地方,有一對年輕人結婚,婚後生育,他的太太因難產而死,遺下一孩子。
他忙生活,又忙於看家,因沒有人幫忙看孩子,就訓練一只狗,那狗聰明聽話,能照顧小孩,咬著奶瓶喂奶給孩子喝,撫養孩子。
有一天,主人出門去了,叫它照顧孩子。
他到了別的鄉村,因遇大雪,當日不能回來。
第二天才趕回家,狗立即聞聲出來迎接主人。他把房門開一看,到處是血,抬頭一望,床上也是血,孩子不見了,狗在身邊,滿口也是血。
主人發現這種情形,以為狗性發作,把孩子吃掉了,大怒之下,拿起刀來向著狗頭一劈,把狗殺死了。
之後,忽然聽到孩子的聲音,又見他從床下爬了出來,於是抱起孩子;雖然身上有血,但并未受傷。
他很奇怪,不知究竟是怎么一回事,再看看狗身,腿上的肉沒有了,旁邊有一只狼,口里還咬著狗的肉;
狗救了小主人,卻被主人誤殺了,這真是天下最令人驚奇的誤會。
注:誤會的事,是人往往在不了解、無理智、無耐心、缺少思考、未能多方體諒對方,反省自己,感情極為沖動的情況之下所發生。誤會一開始,即一直只想到對方的千錯萬錯;因此,會使誤會越陷越深,弄到不可收拾的地步,
人對無知的動物小狗發生誤會,尚且會有如此可怕嚴重的後果,這樣人與人之間的誤會,則其後果更是難以想像。
2》釘子:
有一個男孩有著很壞的脾氣,於是他的父親就給了他一袋釘子;并且告訴他,每當他發脾氣的時候就釘一根釘子在後院的圍籬上。
第一天,這個男孩釘下了37根釘子。慢慢地每天釘下的數量減少了。
他發現控制自己的脾氣要比釘下那些釘子來得容易些。
終於有一天這個男孩再也不會失去耐性亂發脾氣,他告訴他的父親這件事,父親告訴他,現在開始每當他能控制自己的脾氣的時候,就拔出一根釘子。
一天天地過去了,最後男孩告訴他的父親,他終於把所有釘子都拔出來了。
父親握著他的手來到後院說:你做得很好,我的好孩子。
但看看那些圍籬上的洞,這些圍籬將永遠不能回復成從前。
你生氣的時候說的話將像這些釘子一樣留下疤痕。
如果你拿刀子捅別人一刀,不管你說了多少次對不起,那個傷口將永遠存在。
話語的傷痛就像真實的傷痛一樣令人無法承受。
注:人與人之間常常因為一些彼此無法釋懷的堅持,而造成永遠的傷害。如果我們都能從自己做起,開始寬容地看待他人,相信你(你)一定能收到許多意想不到的結果……幫別人開啟一扇窗,也就是讓自己看到更完整的天空
…
…
3》且慢下手:
大多數的同仁都很興奮,因為單位里調來一位新主管,據說是個能人,專門被派來整頓業務。
可是日一天天過去,新主管卻毫無作為,每天彬彬有禮進辦公室,便躲在里面難得出門,那些本來緊張得要死的壞份子,現在反而更猖獗了。
「他那里是個能人嘛!根本是個老好人,比以前的主管更容易唬!」
四個月過去,就在真正努力為新主管感到失望時,新主管卻發威了……壞份子一律開革,能人則獲得晉升。
下手之快,斷事之準,與四月表現保守的他,簡直像是全然換個人。
年終聚餐時,新主管在酒過三巡之後致詞:“相信大家對我新到任期間的表現,和後來的大刀闊斧,一定感到不解,現在聽我說個故事,各位就明白了:「我有位朋友,買了棟帶著大院的房子,他一搬進去,就將那院子全面整頓
,雜草樹一律清除,改種自己新買的花卉,某日原先的屋主往訪,進門大吃一驚的問:『那最名貴的牡丹哪里去了?』我這位朋友才發現,他竟然把牡丹當草給鏟了。後來他又買了一棟房子,雖然院子更是雜亂,他卻是按兵不動
,果然冬天以為是雜樹的植物,春天里開了繁花;春天以為是野草的,夏天里成了錦蔟;半年都沒有動靜的小樹,秋天居然紅了葉。直到暮秋,它才真正認清哪些是無用的植物,而大力鏟除,并使所有珍貴的草木得以保存。
”
說到這兒,主管舉起杯來:「讓我敬在座的每一位,因為如果這辦公室是個花園,你們就都是其間的珍木,珍木不可能一年到頭開花結果,只有經過長期的觀察才認得出啊!
4》寬大:
這是一個甫自越戰歸來的士兵的故事。
他從舊金山打電話給他的父母,告訴他們:「爸媽,我回來了,可是我有個不情之請。我想帶一個朋友同我一起回家。」
「當然好啊!」他們回答「我們會很高興見到的。」
不過兒子又繼續下去「可是有件事我想先告訴你們,他在越戰里受了重傷,少了一條胳臂和一只腳,他現在走投無路,我想請他回來和我們一起生活。」
「兒子,我很遺撼,不過或許我們可以幫他找個安身之處。」
父親又接著說「兒子,你不知道自己在說些什么。像他這樣殘障的人會對我們的生活造成很大的負擔。我們還有自己的生活要過,不能就讓他這樣破壞了。我建議你先回家然後忘了他,他會找到自己的一片天空的。」
就在此時,兒子掛上了電話,他的父母再也沒有他的消息了。
幾天後,這對父母接到了來自舊金山警局的電話,
告訴他們親愛的兒子已經墜樓身亡了。警方相信這只是單純的自殺案件。
於是他們傷心欲絕地飛往舊金山,并在警方帶領之下到太平間去辨認兒子的遺體。
那的確是他們的兒子沒錯,但驚訝的是兒子居然,只有一條胳臂和一條腿。
故事中的父母就和我們大多數人一樣。要去喜愛面貌姣好或談吐風趣的人很容易,但是要喜歡那些造成我們不便和不快的人卻太難了。我們總是寧愿和那些不如我們健康,美麗或聰明的人保持距離。然而感謝上帝,有些人卻不會
對我們如此殘酷。他們會無怨無悔地愛我們,不論我們多么糟總是愿意接納我們。
今晚在你入睡之前,向上帝禱告,請賜給你力量去接納他人,不論他們是怎么樣的人;請幫助我們了解那些不同於我們的人。每個人的心里都藏著一種神奇的東西稱為「友情」,你不知道它究竟是如何發生何時發生,但你卻知道
它總會帶給我們特殊的禮物。
你也會了解友情是上帝給我們最珍貴的贈與!
朋友就像是稀奇的寶物。他們帶來歡笑,激勵我們成功。
他們傾聽我們內心的話,與我們分享每一句贊美。
他們的心房永遠為我們而敞開。現在就告訴你的朋友你有多在乎他們。把
這篇文章轉寄給所有你認為是朋友的人。
如果這篇文章又回來了,你將知道你擁有了一輩子的朋友。
試想:朋友,您一路看下來之後;一定有很深的感觸吧。
那么,在對別人有所決定與判斷之前,首先,請想想這是否是一個「誤會」,然後,請考慮您是否一定要釘下這個「釘子」,如果可以的話,請「且慢下手」。因為,當您對別人「寬大」之時,即是對您自己寬大
posted @
2006-06-27 22:05 Jerry Cat 閱讀(190) |
評論 (0) |
編輯 收藏
以塌實編碼為榮 以心浮氣躁為恥
以詳細注釋為榮 以注釋殘缺為恥
以勤于測試為榮 以懶于測試為恥
以簡明文檔為榮 以冗余文檔為恥
以注重團隊為榮 以孤傲自大為恥
以刻苦鉆研為榮 以敷衍了事為恥
以善于總結為榮 以不思進取為恥
以質效并進為榮 以單取其一為恥
posted @
2006-06-27 21:41 Jerry Cat 閱讀(880) |
評論 (2) |
編輯 收藏
很多人都覺得自己的程序的界面不那么美觀, 往往VC默認產生的對話框比較單調, 因此很多人往往找到很多其它的控件對對話框進行美化修飾, 例如給靜態控件設置字體, 設置背景顏色等等, 其實這些完全可以由VC自己的WM_CTLCOLOR消息來完成!
WM_CTLCOLOR消息用來完成對EDIT, STATIC, BUTTON等控件設置背景和字體顏色, 其用法如下:
1.首先在自己需要設置界面的對話框上點擊右鍵-->建立類向導-->加入WM_CTLCOLOR消息-->自動生成OnCtlColor()函數, 此函數可以對本對話框的控件的界面外觀做修飾, 用法如下:
將類向導產生的函數做如下修改:
HBRUSH CDialogColor::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
??? HBRUSH hbr = CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
??? // TODO: Change any attributes of the DC here
??? // 設置顯示字體
??? CFont * cFont=new CFont;
??? cFont->CreateFont(16,0,0,0,FW_SEMIBOLD,FALSE,FALSE,0,
??????????????? ANSI_CHARSET,OUT_DEFAULT_PRECIS,
??????????????? CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
??????????????? DEFAULT_PITCH&FF_SWISS,"Arial");
??? // 對特定的控件做修改
??? switch()
??? {
??????? case CTLCOLOR_STATIC: //對所有靜態文本控件的設置
??????? {
??????????? pDC->SetBkMode(TRANSPARENT);
??????????? //設置背景為透明
??????????? pDC->SetTextColor(RGB(255,255,0)); //設置字體顏色
??????????? pWnd->SetFont(cFont); //設置字體
??????????? HBRUSH B = CreateSolidBrush(RGB(125,125,255));
??????????? //創建畫刷
??????????? return (HBRUSH) B; //返回畫刷句柄
??????? }
??????? case CTLCOLOR_EDIT: //對所有編輯框的設置
??????? {
??????????? pDC->SetBkMode(TRANSPARENT);
??????????? pDC->SetTextColor(RGB(255,255,0));
??????????? pWnd->SetFont(cFont);
??????????? HBRUSH B = CreateSolidBrush(RGB(125,125,255));
??????????? return (HBRUSH) B;
??????? }
??????? default:
??????????? return CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
??? }
}
注:case的類別有以下幾種:
CTLCOLOR_BTN 按鈕控件
CTLCOLOR_DLG 對話框
CTLCOLOR_EDIT 編輯框
CTLCOLOR_LISTBOX 列表框
CTLCOLOR_MSGBOX 消息框
CTLCOLOR_SCROLLBAR 滾動條
CTLCOLOR_STATIC 靜態文本
2.你可能覺得對所有的控件使用統一的界面設置覺得不自由, 其實VC同樣可以對特定的ID的控件進行設置, 方法如下:
switch (pWnd->GetDlgCtrlID())
{
??? //針對ID為IDC_CTL1, IDC_CTL2和IDC_CTL3的控件進行同樣的設置
??? case IDC_CTL1:
??? case IDC_CTL2:
??? case IDC_CTL3:
??? {
??????? pDC->SetBkMode(TRANSPARENT);
??????? pDC->SetTextColor(RGB(255,255, 0));
??????? pWnd->SetFont(cFont);
??????? HBRUSH B = CreateSolidBrush(RGB(125,125,255));
??????? return (HBRUSH) B;
??? }
??? default:
??????? return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
posted @
2006-06-24 22:30 Jerry Cat 閱讀(656) |
評論 (0) |
編輯 收藏
[轉]GridCtrl使用詳解
在單文檔中的使用方法
步驟一 初始化
在CView類的.h頭文件中包含文件:
??? #include "Gridctrl.h"
并且手寫加入如下的成員函數:
????CGridCtrl * m_pGridCtrl;
步驟二 構造與析構
構造函數中:
???m_pGridCtrl = NULL;
析構函數中:
???if(m_pGridCtrl)
???????delete m_pGridCtrl;
步驟三 如果需要打印功能的話添加同名打印函數代碼
在CView類的OnBeginPrinting()函數中添加如下代碼:
if(m_pGridCtrl)
????m_pGridCtrl->OnBeginPrinting(pDC,pInfo); //簡單吧,這就是類的好處
其它兩個打印函數也一樣的做法.
步驟四 在OnInitaUpdate()函數中或者你自己添加的要顯示Grid的消息函數中如下初始化:
//創建非模式對話框
CDlg *dlg;
dlg=new CDlg();
dlg->Create(IDD_Dlg,this);
//初始化GridCtrl控件
if(m_pGridCtrl!=NULL)
{
delete m_pGridCtrl;
m_pGridCtrl=NULL;
}
if (m_pGridCtrl == NULL)
{
// Create the Gridctrl object
m_pGridCtrl = new CGridCtrl;
if (!m_pGridCtrl) return 0;
// Create the Gridctrl window
CRect rect;
GetClientRect(rect);
m_pGridCtrl->Create(rect, this, 100);
// fill it up with stuff
m_pGridCtrl->SetEditable(false);
m_pGridCtrl->SetTextBkColor(RGB(0xFF, 0xFF, 0xE0)); //黃色背景
m_pGridCtrl->EnableDragAndDrop(false);
try {
m_pGridCtrl->SetRowCount(k); //設置行數為k行
m_pGridCtrl->SetColumnCount(4); //k列
m_pGridCtrl->SetFixedRowCount(1); //標題行為一行
m_pGridCtrl->SetFixedColumnCount(1); //同上
}
catch (CMemoryException* e)
{
e->ReportError();
e->Delete();
return 0;
}
//填充列標題
int row=0;
for(int col=0;col<4;col++)
{
GV_ITEM Item;
Item.mask = GVIF_TEXT|GVIF_FORMAT;
Item.row = row;
Item.col = col;
if(col==0){
Item.nFormat = DT_CENTER|DT_WORDBREAK;
Item.strText.Format(_T("【類別】"),col);
}
else if(col==1){
Item.nFormat = DT_LEFT|DT_WORDBREAK;
Item.strText.Format(_T("第一列"),col);
}
else if(col==2){
Item.nFormat = DT_LEFT|DT_WORDBREAK;
Item.strText.Format(_T("第二列"),col);
}
m_pGridCtrl->SetItem(&Item);
}
// fill rows/cols with text
for (row = 1; row < k; row++)
for (col = 0; col < h; col++)
{
GV_ITEM Item;
Item.mask = GVIF_TEXT|GVIF_FORMAT;
Item.row = row;
Item.col = col;
if (col < 1) { //行標題頭
Item.nFormat = DT_CENTER|DT_VCENTER
|DT_SINGLELINE|DT_END_ELLIPSIS
|DT_NOPREFIX;
Item.strText.Format(_T("%d"),row);
}
else if(col==1){ //第一列的值
Item.nFormat = DT_CENTER|DT_VCENTER
|DT_SINGLELINE|DT_END_ELLIPSIS
|DT_NOPREFIX;
str="aa";
Item.strText.Format(_T("%s"),str);
}else if(col==2){ //第二列第值
Item.nFormat = DT_CENTER|DT_VCENTER
|DT_SINGLELINE|DT_END_ELLIPSIS
|DT_NOPREFIX;
CString str;
str="bb";
Item.strText.Format(_T("%s"),str);
}
m_pGridCtrl->SetItem(&Item);
}
m_pGridCtrl->AutoSize();
//--------------設置行列距------------------
for(int a=1;a<m;a++)
m_pGridCtrl->SetRowHeight(a,21); //設置各行高
m_pGridCtrl->SetRowHeight(0,24); //設置0行高
m_pGridCtrl->SetColumnWidth(1,110); //設置2列寬
m_pGridCtrl->SetColumnWidth(2,160); //設置3列寬
m_pGridCtrl->SetColumnWidth(3,100); //設置4列寬
}
上例取自實際工程,稍有修改!
部分注釋:
void SetVirtualMode(TRUE)
//設為虛模式
BOOL SetRowCount(int nRows) //設置總的行數。
BOOL SetFixedRowCount(int nFixedRows = 1)//設置固定的行數據
BOOL SetColumnCount(int nCols) //設置列數
BOOL SetFixedColumnCount(int nFixedCols = 1)//設置固定的列數
步驟五: 添加WM_SIZE消息,調整控件的界面占屏幕大小
??if(m_pGridCtrl->GetSafeHWnd())
???{
??????CRect rect;
?????GetClientRect(rect);
?????m_pGridCtrl->MoveWindow(rect);
???}
?在對話框中的使用方法
步驟一 創建數據顯示表格對話框
在資源管理器中新創建一個對話框,假設為CDlgTestReportBox。 從工具箱中加入Custom Control,就是人頭像的那個,將其區域拉伸至要顯示數據表格的大小,充滿整個對話框。
在CDlgTestReportBox類的頭文件中:
#include "GridCtrl.h"
再定義成員變量:
CGridCtrl* m_pGrid;
添加OnShowWindow()消息處理函數如下:
void CDlgTestReportBox::OnShowWindow(BOOL bShow, UINT nStatus)
{
CDialog::OnShowWindow(bShow, nStatus);
// TODO: Add your message handler code here
if(m_pGrid!=NULL)
{
delete m_pGrid;
m_pGrid=NULL;
}
if(m_pGrid==NULL)
{
m_pGrid=new CGridCtrl;
CRect rect;
GetDlgItem(IDC_ReportAera)->GetWindowRect(rect); //得到顯示區域
ScreenToClient(&rect);
m_pGrid->Create(rect,this,100);
m_pGrid->SetEditable(false);
m_pGrid->SetTextBkColor(RGB(0xFF, 0xFF, 0xE0)); //黃色背景
try
{
m_pGrid->SetRowCount(10); //初始為10行
m_pGrid->SetColumnCount(11); //初始化為11列
m_pGrid->SetFixedRowCount(1); //表頭為一行
m_pGrid->SetFixedColumnCount(1); //表頭為一列
}
catch (CMemoryException* e)
{
e->ReportError();
e->Delete();
// return FALSE;
}
for (int row = 0; row < m_pGrid->GetRowCount(); row++)
for (int col = 0; col < m_pGrid->GetColumnCount(); col++)
{
//設置表格顯示屬性
GV_ITEM Item;
Item.mask = GVIF_TEXT|GVIF_FORMAT;
Item.row = row;
Item.col = col;
if(row==0&&col==0) //第(0,0)格
{
Item.nFormat = DT_CENTER|DT_WORDBREAK;
Item.szText.Format(_T("報表顯示"),col);
}
else if (row < 1) //設置0行表頭顯示
{
Item.nFormat = DT_CENTER|DT_WORDBREAK;
Item.szText.Format(_T(" 項目%d"),col);
}
else if (col < 1) //設置0列表頭顯示
{
if(row< m_pGrid->GetRowCount()-4)
{
Item.nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
Item.szText.Format(_T("第%d次"),row);
}
}
else
{
Item.nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
Item.szText.Format(_T(""),2);
}
m_pGrid->SetItem(&Item);
}
m_pGrid->Invalidate();
}
//--------------設置行列距------------------
for(int a=0;aGetRowCount();a++)
m_pGrid->SetRowHeight(a,16); //設置各行高
m_pGrid->SetColumnWidth(0,58); //設置0列寬
for(int b=1;bGetColumnCount();b++)
m_pGrid->SetColumnWidth(b,59); //設置各列寬
}
步驟二 嵌入上面的對話框 顯示數據
在你需要顯示數據的對話框上的頭文件中,假設為CDlgTest,加入
#include "GridCtrl.h"
CDlgTestReportBox* m_pTestReportBox;
將數據顯示對話框放入你的對話框相應位置上,在CDlgTest::OnInitDialog() 中:
if(!m_pTestReportBox)
{
?????m_pTestReportBox=new CDlgTestReportBox(this);
}
m_pTestReportBox->Create(IDD_DlgTestReportBox,this);
//定義區域變量
CRect rectDraw;
GetDlgItem(IDC_AeraReport)->GetWindowRect(rectDraw);
ScreenToClient(&rectDraw); //動態測試數據顯示區域rectDraw
//將對應的對話框放到指定區域
m_pTestReportBox->MoveWindow(rectDraw);
m_pTestReportBox->ShowWindow(SW_SHOW);
自定義填充數據的函數:CDlgTest::FillGrid() 如下:
CGridCtrl* pGrid=m_pTestReportBox->m_pGrid;
for (int row = pGrid->GetRowCount()-1; row >= pGrid->GetRowCount()-3; row--)
{
for (int col = 1; col <= pGrid->GetColumnCount(); col++)
{
GV_ITEM Item;
Item.mask = GVIF_TEXT|GVIF_FORMAT;
Item.row = row;
Item.col = col;
if(row==pGrid->GetRowCount()-3&&col>0) //平均值
{
if(col==10){
Item.nFormat = DT_CENTER|DT_WORDBREAK;
Item.szText.Format(_T(" %6.2f "),avjch);
}
else{
Item.nFormat = DT_CENTER|DT_WORDBREAK;
Item.szText.Format(_T(" %6.2f "),av[col-1]);
}
}
pGrid->SetItem(&Item); //提交數據
if(row==0||col==0)
{
COLORREF clr = RGB(0, 0, 0);
pGrid->SetItemBkColour(row, col, clr);
pGrid->SetItemFgColour(row, col, RGB(255,0,0));
}
}//循環結束
pGrid->Invalidate();
}
好累啊,忙了一天時間終于寫完了!
posted @
2006-06-24 19:50 Jerry Cat 閱讀(5418) |
評論 (5) |
編輯 收藏
[轉]深入 printf / wprintf / console下的unicode output
1. printf 只能提供ANSI/MB 的輸出,不支持輸出unicode stream.
例如:
wchar_t?test[]
=
L
"
測試1234
"
;
printf(
"
%s
"
,test);
是不會正確輸出的
2.wprintf 同樣不會提供unicode output,
?? 但是他會把wchar_t的string轉為locale的SB/MB字符編碼,然后輸出
例如:
wchar_t?test[]?
=
?L
"
測試Test
"
;
wprintf(L
"
%s
"
,test);
會輸出??1234之類的字符串,或者不輸出任何結果
因為wprintf沒有辦法把L"測試Test"轉為默認的ANSI,需要設置locale
setlocale(LC_ALL,
"
chs
"
);
wchar_t?test[]?
=
?L
"
測試Test
"
;
wprintf(L
"
%s
"
,test);
會有正確的輸出
綜上:?
CRT I/O functions do not provide Unicode output.
3. Window console自從NT4就是一個真正的unicode console
不過輸出unicode string,只有使用Windows API, WriteConsoleW
例如:
wchar_t?test[]?
=
?L
"
測試1234
"
;
DWORD?ws;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),test,wcslen(test),
&
ws,NULL);
可以正確的輸出而不需要設置locale,因為是真正的unicode的輸出,跟codepage無關
4. 如何實現跨平臺的console output
??? 不要使用wchar_t和wprintf,因為這些都依賴于編譯器.
???? ICU是IBM的一個成熟的跨平臺支持unicode的libary,推薦使用
以下是ICU的uprintf實現
void
?uprintf(
const
?UnicodeString?
&
str)?{
????
char
?
*
buf?
=
?
0
;
????int32_t?len?
=
?str.length();
????int32_t?bufLen?
=
?len?
+
?
16
;
????int32_t?actualLen;
????buf?
=
?
new
?
char
[bufLen?
+
?
1
];
????actualLen?
=
?str.extract(
0
,?len,?buf
/*
,?bufLen
*/
);?
//
?Default?codepage?conversion
????buf[actualLen]?
=
?
0
;
????printf(
"
%s
"
,?buf);
????delete?buf;
}
它也是先把Unicode string轉化為本地的codepage,然后printf,雖然也不是unicode output,但是跨平臺,大多數情況會工作得很好。
posted @
2006-06-22 02:11 Jerry Cat 閱讀(466) |
評論 (0) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
讀VC++內幕之體悟 - 04
作者: Jerry Cat
時間: 2006/06/17
鏈接: http://www.shnenglu.com/jerysun0818/archive/2006/06/17/8669.html
4
.?? ActiveX控件最突出的特點是其屬性和方法。屬性有符號化的名字,這些名字對應著內部的整數索引。客戶可通過一個整數索引存取相應的屬性值。ActiveX控件的方法與函數很類似。
posted @
2006-06-17 19:48 Jerry Cat 閱讀(533) |
評論 (0) |
編輯 收藏
[轉]我的生財之道 - 計算機編程相關
本人長期高價代做計算機系作業、課程設計及畢業設計。作業100元,課程設計1000元,畢業設計5000元。明碼標價童叟無欺,保證質量保證原創。上海交大(你們幸福著哩,沾陳進叫獸的光哦)學生可享受九折優惠; 湖南長沙國防科技大(你們狗日的真幸運,抄FreeBSD 5.3搞了個叫凄淋的偽操作系統說國防,軍人的保家衛國全靠它哩)八五折優惠。技術交流及技術咨詢不在上述之列。
posted @
2006-06-15 19:14 Jerry Cat 閱讀(348) |
評論 (0) |
編輯 收藏
[轉]c++中的引用新解
c++中的引用又稱為別名.
1. 引用必須被初始化,即必須指向一個對象.
?int nTemp = 10;
int &refTemp = nTemp;
2.初始化之后就不能再指向其他對象.如果用一個引用給另一個引用賦值,那么被改變的是被引用的對象而不是引用本身.
int nOther = 20;
refTemp = nOther; //此時nTemp中的值為20,但是&refTemp和&nTemp是相同的.
3.用const修飾的引用可以用不同類型的對象初始化(只要能從一種類型轉換到另外一種類型),也可以是不可尋址的值.能夠這樣的原因是因為:編譯器做了手腳.
double dTemp = 1024;
const int &refTemp = dTemp; //&dTemp和&refTemp是不同的.
編譯之后成為:
double dTemp = 1024;
int nTemp = dTemp;
const int &refTemp = nTemp;
4.不允許非const引用指向需要臨時對象的對象或值.
posted @
2006-06-15 07:02 Jerry Cat 閱讀(333) |
評論 (0) |
編輯 收藏