1. 《The C++ Programming Language》 (Special 3rd Edition) by Bjarne Stroustrup
C++之父著作的大頭作,非常不錯(cuò),很厚,對(duì)C++介紹的非常詳細(xì)。
2. 《The Design and Evolution of C++》 by Bjarne Stroustrup
如果你只打算購(gòu)買(mǎi)一本書(shū),那就選擇1,如果還想要第二本 — 那就是這兩本了。它們的作者是 C++語(yǔ)言的創(chuàng)建者。Stroustrup的文字語(yǔ)言絲毫不遜色于他所創(chuàng)建的程序語(yǔ)言。它們可以使你免于誤入歧途。
3. 《Effective C++》: 50 Specific Ways to Improve Your Programs and Designs
by Scott Meyers
4. 《More Effective C++》: 35 New Ways to Improve Your Programs and Designs
by Scott Meyers
5. 《Effective STL》: 50 Specific Ways to Improve Your Use of the Standard Template Library by Scott Meyers
我強(qiáng)烈推薦Meyers這個(gè)系列。它們是菜鳥(niǎo)進(jìn)階必讀之作。游刃有余的技術(shù),高超的寫(xiě)作技巧。Meyers可能是世界上最優(yōu)秀的C++技術(shù)作家。
6. 《The C++ Standard Library》 : A Tutorial and Reference by Nicolai M. Josuttis
C++標(biāo)準(zhǔn)庫(kù)字典式著作。內(nèi)容全面,結(jié)構(gòu)清晰。
7. 《C++ Templates》: The Complete Guide by David Vandevoorde,
Nicolai M. Josuttis Alexandrescu的Modern C++ Design閱讀門(mén)檻很高,這本書(shū)可以充當(dāng)你的墊腳石。單單閱讀The C++ Standard Library或許并不足以使你具備定制、擴(kuò)充標(biāo)準(zhǔn)庫(kù)組件的能力,這本書(shū)可以助你一臂之力。對(duì)于任何希望進(jìn)入模板編程領(lǐng)域的C++程序員來(lái)說(shuō),這是一本必讀之作。
8. 《Modern C++ Design》: Generic Programming and Design Patterns Applied
by Andrei Alexandrescu
一本天才的著作!泛型模式,無(wú)限延伸你的視野,足以挑戰(zhàn)任何一名C++程序員的思維極限。這本書(shū)幾乎可以滿足你對(duì)C++模板的所有幻想。
9. 《Design Patterns》
by Erich Gamma , Richard Helm, Ralph Johnson, John Vlissides
設(shè)計(jì)可復(fù)用的面向?qū)ο蟮能浖阈枰莆赵O(shè)計(jì)模式。這并不是一本專(zhuān)門(mén)針對(duì)C++程序員的著作,但它采用了C++(和Smalltalk)作為主要示例語(yǔ)言,C++程序員尤其易于從中受益。學(xué)習(xí)設(shè)計(jì)模式,這本書(shū)需要一而再、再而三的咀嚼。
首先我們必須約定一些法則,我們用Y、M、D分別表示年、月、日,用數(shù)字0-6分別表示星期日-星期六,這樣我們就可以開(kāi)始推導(dǎo)我們的公式了。
我們知道2002年9月1號(hào)為星期日,如果我們要想知道2002年9月10號(hào)為星期幾,可以這樣算:(0+(10-1))%7=(0+9)%7=2,即星期二。同樣可算得2002年9月20號(hào)為:(0+(20-1))%7=(0+19)%7=5,即星期五。但是這樣算需要把日期減1,不太方便,為了解決這個(gè)問(wèn)題,我們可以假設(shè)每個(gè)月有一個(gè)0號(hào),由于2002年9月1號(hào)為星期日,那么2002年9月0號(hào)為星期六,這樣算9月10號(hào),只需代入10既(6+10)%7=2。事實(shí)上,9月0號(hào)也就是8月31號(hào),每個(gè)月0號(hào)的星期數(shù)實(shí)際上就是每個(gè)月1號(hào)的前一天的星期數(shù)。我把這個(gè)星期數(shù)稱(chēng)之為每個(gè)月的代碼。有了這個(gè)代碼,要算這個(gè)月任一天的星期數(shù)都好辦了。
以上討論的是一年中每個(gè)月的代碼,事實(shí)上對(duì)于每年也有一個(gè)代碼,這個(gè)代碼就是每年1月0號(hào)(即1月1號(hào)的前一天)的星期數(shù),也就是一月份的代碼。如果我們能夠找到每年的代碼之間的關(guān)系,那么要計(jì)算萬(wàn)年歷就易如反掌了。
(一)推算年的代碼公式
我們都知道,平年一年有365天,即52周多1天。閏年為366天即52周多2天。我們先只考慮平年的情況。
假設(shè)第N年的代碼為W,則第N+1年的代碼為(W+1)%7,而第N+K年的代碼則為(W+K)%7。這是因?yàn)閺牡贜年到第N+K年共經(jīng)過(guò)了K年,每過(guò)一年也就是過(guò)了52周余1天,經(jīng)過(guò)K年也就是過(guò)了52*K周余K天,將多余的天數(shù)K加上第N年的代碼W再對(duì)7取模,所得也就是第N+K年的代碼了。
下面我們把閏年也考慮進(jìn)來(lái)。判斷閏年的規(guī)則是,能被4整除,并能被100和400同時(shí)整除的年份就是閏年。所以從第N年到第N+K年間共有K/4 -K/100+K/400個(gè)閏年,而每個(gè)閏年有52周余2天,要比平年多余了1天,即共多余了K/4-K/100+K/400天。我們應(yīng)該把這些天也加進(jìn)去,所以第N+K年的代碼應(yīng)為(W+K+K/4-K/100+K/400)%7。
這樣子是不是就考慮完全了呢?并非如此,我們還有兩點(diǎn)沒(méi)考慮到。第一點(diǎn)是第N年是不是閏年。如果第N年是閏年的話,它本身就是52周余2天,而我們?cè)谏厦鎱s是把它當(dāng)作平年來(lái)計(jì)算的,少算了1天,應(yīng)加上。所以在第N年為閏年的時(shí)候上式應(yīng)為(W+(K+1)+K/4-K/100+K/400)%7。第二點(diǎn)是第N+K年是不是閏年。如果第N+K年是閏年,雖然它有52周余2天,但只有在算第N+(K+1)年的時(shí)候,才需要多加它那一天,而在算第N+K年的時(shí)候不需要多加這1天,因此我們必須將上式改為(W+(K+1)+(K-1)/4-(K-1)/100+(K-1)/400)%7(注意千萬(wàn)不能改為(W+(K+1)+(K/4-K/100+K/400-1))%7=(W+K+K/4-K/100+K/400)%7)。
由此我們可以得出當(dāng)?shù)贜年為閏年時(shí),第N+K年的代碼計(jì)算式為:
A=(W+(K+1)+(K-1)/4-(K-1)/100+(K-1)/400)%7為了方便計(jì)算,我們可以取N為0,也就是假設(shè)公元元年的代碼為W。因?yàn)楣暌彩情c年,符合上式,那么當(dāng)我們輸入的年份為Y時(shí),此時(shí)就有K=Y,也就是說(shuō)第Y年的代碼為
A=(W+(Y+1)+(Y-1)/4-(Y-1)/100+(Y-1)/400)%7接下來(lái)的問(wèn)題就是W究竟是一個(gè)什么數(shù)了,下面我們就來(lái)解決這個(gè)問(wèn)題。
我們已經(jīng)知道2002年1月1號(hào)為星期二,它的前一天為星期一,那也就是說(shuō)2002年的代碼就是1,由此我們可得
(W+(2002+1)+(2002-1)/4-(2002-1)/100+(2002-1)/400)%7=1
即
(W+2488)%7=1
(W+3)%7=1
這樣我們就可求得W=5。我們的公式就變成了如下形式
A=(5+(Y+1)+(Y-1)/4-(Y-1)/100+(Y-1)/400)%7有了這個(gè)公式,我們就可以算公元后任意一年的代碼了,但還不能算公元前的,我們還需要再改進(jìn)一下,得出公式(1):
(1)Ayear= Y>0 ? (5+(Y+1)+(Y-1)/4-(Y-1)/100+(Y-1)/400)%7
: (5 + Y + Y/4 - Y/100 + Y/400) % 7
這樣就OK了。不過(guò)這又導(dǎo)致了另一個(gè)問(wèn)題:Y<0時(shí),算得的A有可能小于0。這個(gè)問(wèn)題我們暫且留下,待會(huì)再解決。
(二)推算月的代碼公式
年的問(wèn)題解決了,月怎么辦呢?請(qǐng)看下表:
月份
代碼
差值
一月
A
0
二月
A+3
3
三月
A+3
3
四月
A+6
6
五月
A+1
1
六月
A+4
4
七月
A+6
6
八月
A+2
2
九月
A+5
5
十月
A
0
十一月
A+3
3
十二月
A+5
5
表中的A為當(dāng)年的代碼。由這個(gè)表我們可以看出,月與月之間也有一定的關(guān)系。由此我們可以推出下面的公式(2):
(2)Amonth=M>2 ? (Ayear+2*(M+1)+3*(M+1)/5)%7
: (Ayear+2*(M+2)+3*(M+2)/5)%7
但是上表所反映的僅為平年的情況,若Y為閏年,則在M大于2時(shí),每個(gè)月的代碼還需再加1。這可用一個(gè)IF語(yǔ)句解決:
(3)if (((Y%4==0 && Y%100!==0) || (Y%400==0)) && M > 2)
Amonth = (Amonth+1)%7;
現(xiàn)在我們回到公式(1)中的問(wèn)題。如果Y<0時(shí),使得Ayear<0,那么Ayear最小也只能到-6。大家可以看到,當(dāng)我們將Ayear代入公式(2)時(shí),問(wèn)題就自然解決了。
(三)計(jì)算日期
有了上面的公式,當(dāng)我們輸入日期后,就很容易算出當(dāng)天為星期幾了,而且可以計(jì)算變量允許范圍內(nèi)的任意一天的星期數(shù)。
(4)A = (Amonth+D)%7
(四)寫(xiě)程序
下面給出該萬(wàn)年歷的程序,約莫估計(jì),它可從公元前數(shù)十億年算到公元后數(shù)十億年(即從負(fù)十位數(shù)到正十位數(shù)),而且無(wú)一錯(cuò)漏。
(程序中并沒(méi)有對(duì)輸入的月份和日期進(jìn)行出錯(cuò)處理)
#include <stdio.h>
char *week[] = {"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"};
void main()
{
int Y;
int M;
int D;
int A;
printf("
Enter year:");
scanf("%d",&Y);
printf("
Enter month:");
scanf("%d",&M);
printf("
Enter date:");
scanf("%d",&D);
//下面的四條語(yǔ)句用來(lái)計(jì)算輸入日期的星期數(shù),是程序的核心部分,缺一不可
A = Y > 0 ? (5 + (Y + 1) + (Y - 1)/4 - (Y - 1)/100 + (Y - 1)/400) % 7
: (5 + Y + Y/4 - Y/100 + Y/400) % 7;
A = M > 2 ? (A + 2*(M + 1) + 3*(M + 1)/5) % 7
: (A + 2*(M + 2) + 3*(M + 2)/5) % 7;
if (((Y%4 == 0 && Y%100 != 0) || Y%400 == 0) && M>2)
{
A = (A + 1) % 7;
}
A = (A + D) % 7;
printf("
I's a %s.
",week[A]);
}
《轉(zhuǎn)貼》
幾年以前,Charles Simonyi(他后來(lái)成為微軟的著名程序員)設(shè)計(jì)了一種以前綴為基礎(chǔ)的命名方法,這種方法后來(lái)稱(chēng)為"匈牙利表示法"以記念他.他的思想是根據(jù)每個(gè)標(biāo)識(shí)符所代表的含義給它一個(gè)前綴.微軟后來(lái)采用了這個(gè)思想,給每個(gè)標(biāo)識(shí)符一個(gè)前綴以說(shuō)明它的數(shù)據(jù)類(lèi)型.因此,整型變量的前綴是n,長(zhǎng)整型變量是nl,字符型數(shù)組變量是ca,以及字符串(以空類(lèi)型結(jié)尾的字符數(shù)組)以sz為前綴.這些名字可能會(huì)非常古怪.比如說(shuō):lpszFoo表示"Foo"是一個(gè)指向以空字符為結(jié)尾的字符串的長(zhǎng)整型指針.
這種方法的優(yōu)點(diǎn)是使人能夠通過(guò)變量的名字來(lái)辨別變量的類(lèi)型,而不比去查找它的定義.遺憾的是,這種方法不僅使變量名字非常繞口,而且使改變變量類(lèi)型的工作變得十分艱巨.在Windows3.1中,整型變量為16為寬.如果我們?cè)陂_(kāi)始時(shí)采用了一個(gè)整型變量,但是在通過(guò)30---40個(gè)函數(shù)的計(jì)算之后,發(fā)現(xiàn)采用整型變量寬度不夠,這時(shí)我們不僅要改變這個(gè)變量的類(lèi)型,而且要改變這個(gè)變量在這30--40個(gè)函數(shù)中的名字.
因?yàn)椴磺袑?shí)際,除了一些頑固的Windows程序員外已經(jīng)沒(méi)有人再使用"匈牙利表示法"了.毫無(wú)疑問(wèn),在某種場(chǎng)合它依然存在,但大部分人現(xiàn)在已經(jīng)拋棄它了.一般而言,輸入前綴是一種糟糕的想法,因?yàn)樗炎兞坑谄漕?lèi)型緊緊地綁在了一起.
對(duì)于30行以下的函數(shù),匈牙利方法一般有優(yōu)勢(shì)。
尤其是對(duì)界面編程,有優(yōu)勢(shì)。
但對(duì)于有強(qiáng)烈的算法要求、尤其是有很多抽象類(lèi)型的C++程序,匈牙利方法簡(jiǎn)直是一個(gè)災(zāi)難。
看你用在什么地方。
現(xiàn)在有了很好的IDE工具,如:VC,SourceInsight等.
選中變量,會(huì)自動(dòng)提示告訴你它的聲明和定義,這樣
匈牙利命名法就沒(méi)有很大的必要了.
無(wú)非就是為了程序可讀性較好.
實(shí)際上良好的代碼書(shū)寫(xiě)習(xí)慣比強(qiáng)制使用匈牙利命名法更重要.
系統(tǒng)性。整體性。可讀性。分類(lèi)要清楚。要有注釋?zhuān)?/P>
匈牙利命名法是微軟推廣的一種關(guān)于變量、函數(shù)、對(duì)象、前綴、宏定義等各種類(lèi)型的符號(hào)的命名規(guī)范。匈牙利命名法的主要思想是:在變量和函數(shù)名中加入前綴以增進(jìn)人們對(duì)程序的理解。它是由微軟內(nèi)部的一個(gè)匈牙利人發(fā)起使用的,結(jié)果它在微軟內(nèi)部逐漸流行起來(lái),并且推廣給了全世界的Windows開(kāi)發(fā)人員。下面將介紹匈牙利命名法,后面的例子里也會(huì)盡量遵守它和上面的代碼風(fēng)格。還是那句話,并不是要求所有的讀者都要去遵守,但是希望讀者作為一個(gè)現(xiàn)代的軟件開(kāi)發(fā)人員都去遵守它。
a Array 數(shù)組
b BOOL (int) 布爾(整數(shù))
by Unsigned Char (Byte) 無(wú)符號(hào)字符(字節(jié))
c Char 字符(字節(jié))
cb Count of bytes 字節(jié)數(shù)
cr Color reference value 顏色(參考)值
cx Count of x (Short) x的集合(短整數(shù))
dw DWORD (unsigned long) 雙字(無(wú)符號(hào)長(zhǎng)整數(shù))
f Flags (usually multiple bit values) 標(biāo)志(一般是有多位的數(shù)值)
fn Function 函數(shù)
g_ global 全局的
h Handle 句柄
i Integer 整數(shù)
l Long 長(zhǎng)整數(shù)
lp Long pointer 長(zhǎng)指針
m_ Data member of a class 一個(gè)類(lèi)的數(shù)據(jù)成員
n Short int 短整數(shù)
p Pointer 指針
s String 字符串
sz Zero terminated String 以0結(jié)尾的字符串
tm Text metric 文本規(guī)則
u Unsigned int 無(wú)符號(hào)整數(shù)
ul Unsigned long (ULONG) 無(wú)符號(hào)長(zhǎng)整數(shù)
w WORD (unsigned short) 無(wú)符號(hào)短整數(shù)
x,y x, y coordinates (short) 坐標(biāo)值/短整數(shù)
v void 空
有關(guān)項(xiàng)目的全局變量用g_開(kāi)始,類(lèi)成員變量用m_,局部變量若函數(shù)較大則可考慮用l_用以顯示說(shuō)明其是局部變量。
前綴 類(lèi)型 例子
g_ 全局變量 g_Servers
C 類(lèi)或者結(jié)構(gòu)體 CDocument,CPrintInfo
m_ 成員變量 m_pDoc,m_nCustomers
VC常用前綴列表:
前綴 類(lèi)型 描述 例子
ch char 8位字符 chGrade
ch TCHAR 16位UNICODE類(lèi)型字符 chName
b BOOL 布爾變量 bEnabled
n int 整型(其大小由操作系統(tǒng)決定) nLength
n UINT 無(wú)符號(hào)整型(其大小由操作系統(tǒng)決定) nLength
w WORD 16位無(wú)符號(hào)整型 wPos
l LONG 32位有符號(hào)整型 lOffset
dw DWORD 32位無(wú)符號(hào)整型 dwRange
p * Ambient memory model pointer 內(nèi)存模塊指針,指針變量 pDoc
lp FAR* 長(zhǎng)指針 lpDoc
lpsz LPSTR 32位字符串指針 lpszName
lpsz LPCSTR 32位常量字符串指針 lpszName
lpsz LPCTSTR 32位UNICODE類(lèi)型常量指針 lpszName
h handle Windows對(duì)象句柄 hWnd
lpfn (*fn)() 回調(diào)函數(shù)指針 Callback Far pointer to CALLBACK function lpfnAbort
Windows對(duì)象名稱(chēng)縮寫(xiě):
Windows對(duì)象 例子變量 MFC類(lèi) 例子對(duì)象
HWND hWnd; CWnd* pWnd;
HDLG hDlg; CDialog* pDlg;
HDC hDC; CDC* pDC;
HGDIOBJ hGdiObj; CGdiObject* pGdiObj;
HPEN hPen; CPen* pPen;
HBRUSH hBrush; CBrush* pBrush;
HFONT hFont; CFont* pFont;
HBITMAP hBitmap; CBitmap* pBitmap;
HPALETTE hPalette; CPalette* pPalette;
HRGN hRgn; CRgn* pRgn;
HMENU hMenu; CMenu* pMenu;
HWND hCtl; CStatic* pStatic;
HWND hCtl; CButton* pBtn;
HWND hCtl; CEdit* pEdit;
HWND hCtl; CListBox* pListBox;
HWND hCtl; CComboBox* pComboBox;