3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ Primer读书笔记(从后向前看)

發(fā)布時(shí)間:2024/3/13 c/c++ 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ Primer读书笔记(从后向前看) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

(從后向前看)
標(biāo)題:重載函數(shù)再論
重載函數(shù)是C++提出來的概念,但是在C中卻未必沒有。比如“1+3”和“1.0+3.0”,雖然都是加法,做的卻不是同的操作:編譯器要因操作數(shù)的不同而調(diào)用不同的加法操作。只是C語言中除了內(nèi)部類型變量可以參與運(yùn)算以外,沒有“類”這么高深的概念。“結(jié)構(gòu)體”也只是內(nèi)存數(shù)據(jù)的組織方法,而不涉及對整個(gè)結(jié)構(gòu)體的處理。所以,在C語言時(shí)代編譯器明明做了類似于重載的事情,卻可以像雷鋒一樣“做好事不留名”。
  C++發(fā)展出了類,并且賦予了“類”很高的期望,類的對象也能像內(nèi)置類型對象一樣參與一切運(yùn)算。那么,就拿加法運(yùn)算來說,編譯器如何知道對某類對象的加法該調(diào)用哪一個(gè)詳細(xì)的操作代碼?于是,即使不出現(xiàn)普通函數(shù)的重載,至少運(yùn)算符是要重載的。
  林銳博士在《高質(zhì)量C++/C編程指南》中為重載函數(shù)的必要性提了另一個(gè)理由:類的構(gòu)造函數(shù)名稱必須與類名相同,而類卻經(jīng)常要定義多個(gè)不同的構(gòu)造函數(shù)。那就只好重載了。
  對于普通程序員來說,我們完全可以不用考慮得這么深。重載函數(shù)給我們至少還帶來了另一個(gè)好處:不用記憶多個(gè)不同的函數(shù)名了,也不用為了給函數(shù)起名而絞盡腦汁了。不過本書還給出了一個(gè)建議:并不是任何時(shí)候都有必要重載函數(shù)的,有的時(shí)候不同的函數(shù)名可以直觀地帶來好多信息,濫用重載只是犧牲了名稱中的信息。
?
標(biāo)題::重載函數(shù)的概念
引用:出現(xiàn)在相同作用域中的兩個(gè)(可以是兩個(gè)以上——偷貓注)函數(shù),如果具有相同的名字而形參表不同,則稱為重載函數(shù)。
  本節(jié)開頭第一句話就給出了重載函數(shù)的定義:重載函數(shù)必須符合兩個(gè)條件:一是出現(xiàn)在相同的作用域中、二是函數(shù)名字相同而形參表不同。
  其中第一個(gè)條件一般人往往是不去想的,其實(shí)函數(shù)名相同而作用域不同的函數(shù)大大存在,比如在MFC中就有。它們是完全不相干的函數(shù)。
  第二個(gè)條件還可以詳說一下:函數(shù)名字相同當(dāng)然不在話下,這是函數(shù)被稱為“重載”的根源。之于形參表不同,可能表現(xiàn)在形參個(gè)數(shù)不同、可能表現(xiàn)在形參類型不同、還可能表現(xiàn)在形參順序不同。
  如果要擴(kuò)展開來說,還可以舉出許多不是重載函數(shù)的情況。
  一、如果既在同一作用域下、名稱也相同、形參表也相同,則后者被視為前者的重復(fù)聲明。——函數(shù)可以重復(fù)聲明,因?yàn)楹瘮?shù)的聲明并不產(chǎn)生目標(biāo)代碼,但是函數(shù)的定義不允許重復(fù)出現(xiàn)。
  二、如果既在同一作用域下、名稱也相同、形參表也相同,但是返回值不同,則后者被視為錯(cuò)誤的聲明。函數(shù)不可以只憑返回值來區(qū)分,因?yàn)檎{(diào)用函數(shù)的時(shí)候只憑名稱和形參來選擇函數(shù),而不憑返回值。再究其原因,一是因?yàn)楹瘮?shù)的返回值可以被丟棄;二來即使不丟棄,將返回值賦予另一個(gè)變量之前沒必要檢查我需要什么樣的返回值,而能否賦值也與函數(shù)本身無關(guān)。
  三、有些時(shí)候看起來形參表不同,實(shí)際上是完全相同的,書本第229頁講了四組這樣的例子:
Record lookup(const Account &acct);
Record lookup(const Account &);//區(qū)別在于有沒有給形參命名
typedef Phone Telno;
Record lookup(const Phone&);
Record lookup(const Telno&);//只是給類型取了個(gè)別名
Record lookup(const Phone&, const Name&);
Record lookup(const Phone&, const Name& = "");//區(qū)別在于給形參提供了默認(rèn)值
Record lookup(Phone);
Record lookup(const Phone);//區(qū)別在于是否const  
  其中第三組可能會(huì)讓人產(chǎn)生函數(shù)的形參個(gè)數(shù)不同的假像,其實(shí)可缺省的形參并沒有減少形參的個(gè)數(shù)。第四組有點(diǎn)不容易搞清:因?yàn)橛械臅r(shí)候可以憑是否const來重載,比如引用傳遞和指針傳遞。
?
標(biāo)題::文件的組織
一個(gè)程序往往由多個(gè)源文件組成,這些代碼究竟應(yīng)該放在哪個(gè)源文件里、哪些代碼可以放在同一個(gè)源文件里、哪些代碼必需分開放。這是一個(gè)管理層面的問題。
  說它是管理層面的問題,是因?yàn)檫@些代碼的組織往往沒有惟一的準(zhǔn)則。但是它們還是有一定的規(guī)律的。
  首先,軟件的維護(hù)是一個(gè)復(fù)雜的系統(tǒng)工程。代碼的組織應(yīng)該有利于維護(hù)。應(yīng)該盡量把直接相關(guān)的內(nèi)容放在同一文件、不相關(guān)的內(nèi)容放在不同的文件里。如果這些代碼還有親和疏,那就要分不同的文件夾來存放了。
  其次,軟件的代碼是一個(gè)嚴(yán)格的組織體系。不同的內(nèi)容之間可能是并列的,也可能有必要的先后關(guān)系。于是在“#include”的時(shí)候要注意順序。
  最后,也是最重要的一點(diǎn),有些代碼在同一工程中可以重用(或必須重用),有些代碼在同一個(gè)工程中只能出現(xiàn)一次??梢灾赜玫挠蓄惖穆暶?、函數(shù)的聲明、變量的聲明等,不可以重用的是類的實(shí)體、函數(shù)的實(shí)體、變量的定義等。那么,把可以重用的內(nèi)容放在h文件中,把不可以重用的放在cpp文件中是一個(gè)好辦法。
  拿類的聲明和類的實(shí)體為例,如果把一個(gè)類的所有內(nèi)容一古腦放在同一個(gè)文件中,將可能出現(xiàn)問題。因?yàn)樵谄渌玫筋悓?shí)例的地方都必須讓類的聲明“可見”,所以我們往往在文件頭部加個(gè)“#include”,結(jié)果類的實(shí)體也被編譯多次,在連接時(shí)產(chǎn)生沖突。
  在前文中曾提到過,內(nèi)聯(lián)函數(shù)是惟一允許(也是必須)在編譯時(shí)讓函數(shù)實(shí)體可見的的函數(shù)。所以內(nèi)聯(lián)函數(shù)可以放在h文件中。C++規(guī)則中有一句正好與此照應(yīng):在類的聲明中直接寫出的函數(shù)被認(rèn)為是內(nèi)聯(lián)函數(shù)。
  Visual C++給類的文件起默認(rèn)名時(shí),文件名往往與類名一致。如果類名由“C”開頭,則文件會(huì)是除去開頭的“C”字以外的其它文字。如類“CMyClass”,它的代碼存放在以下兩個(gè)文件中:“MyClass.h”和“MyClass.cpp”中。原因是VC++建議類名以C開頭,至于為什么在文件名中不出現(xiàn)開頭的“C”,可能是出于微軟的習(xí)慣吧。
?
標(biāo)題::類的構(gòu)造函數(shù)
引用:構(gòu)造函數(shù)是特殊的成員函數(shù)。
  筆記:構(gòu)造函數(shù)的確是一類“特殊”的成員函數(shù)。它的特殊性至少表現(xiàn)在以下幾個(gè)方面:一是它的調(diào)用不用程序員操心,只要類對象被創(chuàng)建它就會(huì)被調(diào)用,而且它不允許被程序員顯式地調(diào)用。二是它們是必需的,如果程序員偷懶,編譯器將自動(dòng)創(chuàng)建簡單的構(gòu)造函數(shù)。三是它們的名字不用程序員多考慮,直接與類名相同。四是它們沒有返回值。
  下面詳說這幾個(gè)特性:
  一、它們在類對象被創(chuàng)建時(shí)自動(dòng)調(diào)用,創(chuàng)建對象可能有以下方法:程序中用聲明變量的語句直接聲明創(chuàng)建,或者在程序中用new關(guān)鍵字動(dòng)態(tài)創(chuàng)建。這兩種方法都可以創(chuàng)建單個(gè)對象,也都可以創(chuàng)建對象數(shù)組。只要有一個(gè)對象被創(chuàng)建,構(gòu)造函數(shù)就被調(diào)用一次。
  如果程序員想顯式地調(diào)用構(gòu)造函數(shù)那是不行的。正因?yàn)槿绱?#xff0c;構(gòu)造函數(shù)中還有一種特定的部分叫“初始化列表”,通過它程序員可以調(diào)用基類或成員的構(gòu)造函數(shù)。必竟類的設(shè)計(jì)千差萬別,如果某個(gè)類的基類或(和)成員有多個(gè)構(gòu)造函數(shù),那么,該類必須能夠指定用哪一個(gè)構(gòu)造函數(shù),否則類的功能將大打折扣。調(diào)用構(gòu)造函數(shù)不是程序員的事,程序員不應(yīng)該管也管不了。初始化列表為解決這個(gè)問題而生,所以只有構(gòu)造函數(shù)才有初始化列表,其它函數(shù)不能有。
  上面說到的“大打折扣”究竟是怎樣的折扣呢?如果不能指定基類和成員用哪一個(gè)構(gòu)造函數(shù),那就只好讓編譯器去挑了,構(gòu)造出來的對象往往不符合要求,只好調(diào)用基類和成員的其它函數(shù),比如賦值函數(shù)或其它進(jìn)行參數(shù)設(shè)定的函數(shù)——當(dāng)然,基類和成員必須包含這樣的函數(shù)。這樣就浪費(fèi)了資源。
  二、類必須包含構(gòu)造函數(shù)——確切地說是必須包含無參數(shù)構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù)——原因是因?yàn)樗鼈兊恼{(diào)用是自動(dòng)的。如果這兩個(gè)函數(shù)根本就沒有,你讓系統(tǒng)如何調(diào)用?所以,C++也不含糊,你要是懶得寫,它就幫你寫一個(gè)簡單的。簡單就意味著至少要喪失一些功能,如果類設(shè)計(jì)得比較復(fù)雜(比如包含指針操作)還可能引起災(zāi)難性事故。
  三、函數(shù)名與類名一致。構(gòu)造函數(shù)的名稱是必須特殊的,即使這個(gè)特殊不表現(xiàn)在與類名相同,也必須找到另一個(gè)規(guī)則來實(shí)現(xiàn)。因?yàn)橄到y(tǒng)要自動(dòng)調(diào)用這些函數(shù),你就必須讓系統(tǒng)知道哪些函數(shù)是構(gòu)造函數(shù)。
  第四個(gè)特性直接改變了C/C++語言的一條規(guī)則:C語言規(guī)定,如果函數(shù)沒有明顯指出返回類型,那么C語言認(rèn)為返回值是int型。C語言之所以可以有這條規(guī)則,一是因?yàn)榉祷豬nt的函數(shù)很多,二是因?yàn)榧词箾]有返回值,也必須指明void。當(dāng)時(shí)制定規(guī)則的人無法預(yù)料到,C++中居然會(huì)出現(xiàn)“連void都不是的返回值”的函數(shù),void雖然表示不返回任何值,必竟與類構(gòu)造函數(shù)的“沒有返回值”是兩碼事。于是,C++新標(biāo)準(zhǔn)規(guī)定:在定義或聲明函數(shù)時(shí),沒有顯式指定返回類型中不合法的。當(dāng)然類的構(gòu)造函數(shù)除外。
  構(gòu)造函數(shù)的出現(xiàn)有它的可行院捅厝恍浴?尚行允怯捎贑++的類允許包含成員函數(shù),既然類可以包含普通的成員函數(shù),那么包含特殊的函數(shù)自然也不在話下。必然性是由于類的對象往往必須經(jīng)過特定的初始化。C++到來之前,C語言中的數(shù)據(jù)類型只是內(nèi)置類型。對于內(nèi)置類型對象,如果忘了初始化,大不了這個(gè)對象失去作用,但是不會(huì)導(dǎo)致大的問題。比如一個(gè)int型值,無論內(nèi)存如何隨機(jī),它的取值范圍都不會(huì)超過int能表達(dá)的范圍,對它進(jìn)行運(yùn)算也不會(huì)產(chǎn)生危險(xiǎn)(溢出不能算危險(xiǎn),即使初始化過的數(shù)據(jù)也不能保證不溢出,而且溢出只是一種邏輯問題)。但是現(xiàn)在的類不這么簡單了,忘了初始化往往將帶來運(yùn)行錯(cuò)誤。于其每次都要考慮數(shù)據(jù)的初始化,還不如把這個(gè)初始化寫成統(tǒng)一的函數(shù),讓系統(tǒng)自動(dòng)調(diào)用來得既安全又方便。
?
?
標(biāo)題::類的成員函數(shù)
類與C語言中的結(jié)構(gòu)體最大的區(qū)別就是類可以帶函數(shù),而結(jié)構(gòu)體只是一個(gè)內(nèi)存組合。所以,要提類就不得不提成員函數(shù)。
  類的成員函數(shù)與普通函數(shù)(全局函數(shù))相比,最根本的區(qū)別是實(shí)現(xiàn)了類的封裝性。封裝性的第一個(gè)表現(xiàn)是訪問權(quán)限:都是函數(shù),但是你能訪問哪個(gè)不能訪問哪個(gè)卻可以設(shè)定。第二個(gè)表現(xiàn)是直觀,通過類成員(或指針)來調(diào)用函數(shù),給人的直覺就是“這是類提供的功能”。你好像“Bird.Fly();”一樣一目了然。
  在理解this指針以前要想徹底理解成員函數(shù)是有困難的,我就曾以為在類的實(shí)例中保存了函數(shù)的副本。要不然,為什么同一個(gè)類的不同對象調(diào)用這個(gè)函數(shù)有不同的效果呢?原來,在函數(shù)所有的形參之外,還有一個(gè)不用你操心的參數(shù)this,它是一個(gè)指針,該指針的目標(biāo)就是函數(shù)的調(diào)用者。這么一說就明白了。
  函數(shù)形參表后加入const就成了“const成員函數(shù)”,這樣的函數(shù)保護(hù)了調(diào)用者自身不被修改。如CString的GetLength()函數(shù),你只能獲取它的長度,不能修改它的內(nèi)容或長度。加入const的作用倒不是怕調(diào)用者修改,而是防止編寫函數(shù)的人不小心改動(dòng)了對象。因?yàn)榘倜芸傆幸皇?#xff0c;萬一在某個(gè)不該修改數(shù)據(jù)的函數(shù)中改變了數(shù)據(jù)(比如將“==”寫成“=”),或者萬一調(diào)用了另一個(gè)非const的成員函數(shù)都將可能引起錯(cuò)誤。在編寫函數(shù)前就先加上const可以記編譯器來幫你檢查。
  這個(gè)const加在形參表的后面顯得有些怪怪的,造成“怪怪的”原因就是因?yàn)楹瘮?shù)的形參表中沒有this,也就沒有能用const來修飾的東西了。林銳說“大概是因?yàn)槠渌胤蕉家呀?jīng)被占用了”并不是根本原因。
?
標(biāo)題::內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)應(yīng)該是為了改善C語言中的宏替換的不足而產(chǎn)生的吧。因?yàn)楹晏鎿Q是預(yù)編譯中直接展開的,展開過程中將產(chǎn)生意想不到的結(jié)果。典型的有“#define MAX(a, b) (a) > (b) ? (a) : (b)”?!皉esult = MAX(i, j)+2;”將被展開為“result = (i) > (j) ? (i) : (j) + 2;”。雖然外面再加一對括號可以解決以上問題,但是“result = MAX(i++, j);”被展開后將導(dǎo)致i被自增1了兩次。(以上例子摘自林銳博士的《高質(zhì)量C++/C編程指南》第66頁,林銳管這叫做“邊際效應(yīng)”)
  C++用內(nèi)聯(lián)來取代宏替換,大大提高了安全性。雖然內(nèi)聯(lián)函數(shù)也是編譯時(shí)展開的,但是它能進(jìn)行安全檢查,還能處理類的成員函數(shù)(原因是內(nèi)聯(lián)函數(shù)能夠處理this指針,宏卻不能)。
  引用:內(nèi)聯(lián)對編譯器來說只是一個(gè)建議,編譯器可以選擇忽略這個(gè)建議。
  筆記:也就是說,有些函數(shù)你想內(nèi)聯(lián),編譯器也不一定會(huì)采納。因?yàn)閮?nèi)聯(lián)函數(shù)雖然減少了函數(shù)調(diào)用的開銷,卻增加了程序的體積。
  內(nèi)聯(lián)函數(shù)是唯一允許實(shí)體多次被編譯的函數(shù)。原因是編譯器必須先編譯這個(gè)函數(shù)體,才能在編譯函數(shù)調(diào)用的地方進(jìn)行合理地展開。這就說明在多個(gè)CPP文件組成的工程中,可能有不止一個(gè)CPP文件中要有函數(shù)的實(shí)體。既然這樣,就放進(jìn)頭文件吧。
對本文本的評論有:
我覺得象這個(gè)max()和以前的數(shù)組越界一類的事,都可以歸納為一句話,那就是,C為我們提供了強(qiáng)大的工具,那些不會(huì)使用的人才會(huì)出現(xiàn)這種錯(cuò)誤.連個(gè)數(shù)組越界也管理不好的,還是去寫武俠小說比較好.
比如火藥發(fā)明了以后,我們可以用來炸山開路什么的,難道因?yàn)橛腥擞糜趹?zhàn)爭,就怪這個(gè)火藥功能不夠完善嗎?
是這樣的,我們不應(yīng)該怪C標(biāo)準(zhǔn)不好,
雖然它不能讓result = MAX(i++, j);這種問題得到解決,
產(chǎn)生i被自增兩次這樣的結(jié)果,程序員應(yīng)該自己去避免。
但是,如果標(biāo)準(zhǔn)有進(jìn)步了,我們倒是因?yàn)樽YR它一下。
?
?
標(biāo)題::局部對象與靜態(tài)局部對象
本節(jié)首先向讀者說明了“名字的作用域”和“對象的生命周期”這兩個(gè)概念,不難,理解了就行了。前者是空間概念:指程序還處在代碼階段的時(shí)候這個(gè)名字的可見范圍,后者是時(shí)間概念:指程序運(yùn)行過程中對象的存在時(shí)間。
  函數(shù)的形參以及函數(shù)內(nèi)部聲明的對象都是局部對象,它們的作用域就是函數(shù)內(nèi)部,但是它們的生命周期卻未必是函數(shù)的執(zhí)行過程。這看起來有點(diǎn)摸不著頭腦,原因在于C++的函數(shù)中允許存在以關(guān)鍵字“static”聲明的靜態(tài)對象。
  也就是說,靜態(tài)對象是這樣一個(gè)對象:它的生命周期很長,可以跨越該函數(shù)的每次調(diào)用,哪怕該函數(shù)每24小時(shí)才調(diào)用一次,它也是全天候存在的。但是要想訪問她,卻只有函數(shù)正在執(zhí)行的時(shí)候才行。
  簽于以上特性,我專門寫了兩個(gè)測試函數(shù),該函數(shù)試途返回局部對象的引用或指針:
int& GetInt()
{
  int t=3;
  return t;//警告
}
int* GetInt2()
{
  int t = 3;
  return &t;//警告
}
  以上兩個(gè)警告產(chǎn)生的原因是函數(shù)返回了臨時(shí)對象的引用或地址。但是如果將t的聲明改成“static int t=3;”就不再顯示警告。
  靜態(tài)局部對象似乎為節(jié)約系統(tǒng)開銷做了準(zhǔn)備。不過我認(rèn)為這個(gè)特性不應(yīng)該被濫用。只有確實(shí)有必要讓對象生命周期跨越多次調(diào)用時(shí)才應(yīng)該把它聲明為靜態(tài)(比如統(tǒng)計(jì)函數(shù)被調(diào)用的次數(shù))。否則將提高造成BUG的可能性,使“高效率”的程序成為空中樓閣。
標(biāo)題::默認(rèn)實(shí)參
沒什么比偷懶更舒服的了,所以我喜歡允許默認(rèn)實(shí)參的函數(shù),我還喜歡寫允許默認(rèn)實(shí)參的函數(shù)。
  在形參表中,如果允許某些形參具有默認(rèn)值,則它們必須按從右到左的方向排列。以上這個(gè)規(guī)定C++與BASIC是一樣的,但是C++與BASIC還有一點(diǎn)區(qū)別,就是在函數(shù)調(diào)用時(shí),C++必須從右邊開始缺省實(shí)參,而BASIC卻可以任意缺省而不顧次序(只要有逗號表示那里缺了個(gè)東西即可)。所以,同樣設(shè)計(jì)函數(shù),C++比BASIC要多考慮一個(gè)問題:“設(shè)計(jì)帶有默認(rèn)實(shí)參的函數(shù),其中部分工作就是排列形參,使最少使用默認(rèn)實(shí)參的表參排在最前,最可能使用默認(rèn)實(shí)參的形參排在最后。”
  形參的默認(rèn)值竟究寫在聲明中還是實(shí)體中?我曾經(jīng)試過,在某些情況下寫在聲明中或?qū)嶓w中一樣可行。但是,事實(shí)上寫在實(shí)體中是錯(cuò)誤的做法。只有當(dāng)函數(shù)實(shí)體和函數(shù)調(diào)用在同一個(gè)源文件中,而且函數(shù)實(shí)體在調(diào)用前被編譯時(shí),將形參的默認(rèn)值寫在實(shí)體中才可通過編譯。實(shí)際上對于這種情況,函數(shù)根本就不用聲明。
  將默認(rèn)值寫在實(shí)體中不僅僅是能否通過編譯的問題,還關(guān)系到程序設(shè)計(jì)的理念?!耙皇呛瘮?shù)的實(shí)現(xiàn)本來就與參數(shù)是否有缺省值無關(guān),所以,沒有必要讓缺省值出現(xiàn)在函數(shù)的定義體中。二是參數(shù)的缺省值可能會(huì)改動(dòng),顯然修改函數(shù)的聲明比修改函數(shù)的定義要方便?!?#xff08;《高質(zhì)量C++/C編譯指南》第63頁)
  讀到這里,本書給了我一個(gè)大大的驚詫:原來默認(rèn)實(shí)參的默認(rèn)值還可以是任何表達(dá)式。以前,我一直是這樣寫的:“int GetInt(int i=3);”雖然沒人跟我這樣說過,但是我始終以為后面的默認(rèn)值只能是常量。想不到還可以是需要求值的變量甚至是更復(fù)雜的表達(dá)式:
int GetInt(const int i = 3);
int GetInt2(const int j = GetInt());//居然可以這樣寫
  學(xué)習(xí)了,感謝《C++ Primer》!
?
標(biāo)題::函數(shù)的聲明與實(shí)體
注:本書中提到了“聲明”與“定義”兩個(gè)詞。我倒是認(rèn)為將后者改為“實(shí)體”更好。
  函數(shù)的實(shí)體就是實(shí)實(shí)在在的函數(shù)內(nèi)容,它規(guī)定了這個(gè)函數(shù)怎樣執(zhí)行,這沒有什么好說的。那么函數(shù)為什么還要有聲明呢?
  這樣做的目的之一是告訴編譯器:雖然你還沒有見到函數(shù)本身,不知道函數(shù)是怎樣執(zhí)行的,但是我先告訴你這個(gè)函數(shù)的名稱、參數(shù)與返回值,你就先編譯吧。至于這個(gè)函數(shù)究竟干什么,等到連接的時(shí)候再說。
  設(shè)計(jì)合理的程序,其代碼存放在不同的文件中,函數(shù)的實(shí)體只能有一個(gè),存放在某一個(gè)源文件中。其它源文件中如果要用到這個(gè)函數(shù),就在這個(gè)文件中加入函數(shù)的聲明。
  這樣做的目的之二是函數(shù)的提供者與使用者往往不是同一個(gè)人,甚至不是同一個(gè)企業(yè)。出于種種目的,函數(shù)的提供者可能并不想(或不必)讓使用者知道這個(gè)函數(shù)的具體內(nèi)容,只要使用者能調(diào)用就行。這種情況下,函數(shù)的提供者只需要提供一個(gè)聲明給使用者即可?!狢語言的庫函數(shù)就是這樣的。
  然而“在需要用到函數(shù)的文件中加入函數(shù)的聲明”也有好辦法與笨辦法。將聲明語句重寫一遍自然不難,但是這樣做有兩個(gè)明顯的缺點(diǎn):一是煩瑣易錯(cuò)、二是不易修改。所以,函數(shù)的聲明應(yīng)該放在頭文件中,哪兒要,就在哪兒包含。這就好像我家沒有擺許多盆鮮花而是擺了許多面鏡子。我在哪兒都能看到鮮花,澆水卻只要澆一盆。
  這個(gè)理論也適用于C++的“類”,類的聲明寫進(jìn)頭文件,而實(shí)體卻寫進(jìn)程序文件。不同的是,類的聲明不像函數(shù)的聲明那樣只有一句話,而是一個(gè)完整的結(jié)構(gòu)。
?
?
標(biāo)題::遞歸
引用:直接或間接調(diào)用自己的函數(shù)稱為遞歸函數(shù)。
  引用:遞歸函數(shù)必須定義一個(gè)終止條件,否則函數(shù)將永遠(yuǎn)遞歸下去,這意味著函數(shù)會(huì)一直調(diào)用自身直到程序耗盡。
  初識遞歸的時(shí)候,的確有些不容易搞明白。記得當(dāng)時(shí)的教科書為此畫一個(gè)圖,用一組箭頭來表示要計(jì)算A必須先計(jì)算B、要計(jì)算B又要先計(jì)算C、……,用另一組箭頭表示算好了C就可以算B、算好了B就可以算A?!瓕?shí)例程序與一個(gè)圖結(jié)合,如此擺事實(shí)講道理,要說明遞歸自然稍容易些。
  要寫遞歸函數(shù)就得領(lǐng)悟遞歸的妙用,要寫沒有錯(cuò)誤的遞歸函數(shù)則要領(lǐng)悟其數(shù)學(xué)原理。我倒是覺得這樣的函數(shù)與“數(shù)學(xué)歸納法”有些相通之處。不同的是,數(shù)學(xué)歸納法總是先求邊界條件,再去往無窮方向歸納。而遞歸是從無窮方向向邊界計(jì)算的。函數(shù)如何執(zhí)行,與我們?nèi)绾螌憶]有必然的關(guān)系,于是,我們在寫程序的時(shí)候也可以先寫邊界條件。這樣做可以在程序開頭先把可能的問題給排除掉。“永遠(yuǎn)遞歸下去”的可能性自然被降低。比如求階乘的函數(shù):
//程序一、書上的例子
int factorial(int val)
{
  if (val > 1)
    return factorial(val-1);
  return 1;
}
//程序二
int factorial2(int val)
{
  if (val <= 1)
    return 1;
  return factorial2(val-1);
}
  程序二的寫法與程序一沒有區(qū)別,但可以告訴自己遞歸必須有終止條件。防止一不小心就寫了個(gè)“永遠(yuǎn)”。
  似乎絕大多數(shù)遞歸函數(shù)都可以用循環(huán)來解決。這兩種方法遷就了不同的對象:循環(huán)用少量的計(jì)算機(jī)資源、大量的人力來解決問題,遞歸則用大量的計(jì)算機(jī)資源、少量的人力來解決問題。所以,在計(jì)算機(jī)速度和存儲量都不大的年代,曾有人反對遞歸。
  漢諾塔問題據(jù)說是只有用遞歸才可以解決的問題,其實(shí)只有要求解漢諾塔的移動(dòng)過程才必須用遞歸,如果只要求解移動(dòng)次數(shù),那么用循環(huán)也不成問題。
對本文本的評論有:
階乘的函數(shù)寫錯(cuò)了.
int factorial(int val)
{
  if (val > 1)
    return val* factorial(val-1);
  return 1;
}
暈,我忘了相乘了,哈哈。
?
標(biāo)題::return語句
引用:return語句用于結(jié)束當(dāng)前正在執(zhí)行的函數(shù),并將控制權(quán)返回給調(diào)用此函數(shù)的函數(shù)。
  引用:return語句有兩種形式:reutrn; return expression;……第二種形式提供了函數(shù)的結(jié)果。
  筆記:以上第一句話說了return的兩個(gè)作用之一:結(jié)束函數(shù)。return的作用之二是提供函數(shù)的返回值。
  對于return語句的兩種形式,情式一只能用于無返回值的函數(shù),情式二可以用于有返回值的函數(shù)也可用于無返回值的函數(shù)。
  如果函數(shù)有返回值,就必須用形式二來結(jié)束,這是顯而易見的。
  對于沒有返回值的函數(shù),可以不寫return語句,“隱式的return發(fā)生在函數(shù)的最后一個(gè)語句完成時(shí)”。也可以用形式一來結(jié)束,這種用法一般用在函數(shù)中間,判斷某些條件之后就立即結(jié)束,后面的語句不再執(zhí)行。如果用形式二來返回,那么express必須是另一個(gè)沒有返回值的函數(shù)。如:
void FuncA();
void FuncB()
{
  return FuncA();
}
  個(gè)人認(rèn)為這種寫法不是好習(xí)慣,因?yàn)榭雌饋鞦uncB有了返回值,如果邏輯上有這需要,我認(rèn)為寫成以下格式更好:
void FuncB()
{
  FuncA();
  return;
}
  在BASIC中,函數(shù)的返回值與結(jié)束是由兩個(gè)不同的語句實(shí)現(xiàn)的。前者是一個(gè)給函數(shù)名賦值的語句,后者則是“Exit Function”語句。這種設(shè)計(jì)除了不如C++精練以外,還容易出事。比如在函數(shù)開頭先給函數(shù)名賦一個(gè)默認(rèn)值,然后根據(jù)某些條件給它賦其它特定的值并Exit。如果寫函數(shù)時(shí)不小心漏了某個(gè)賦值語句,函數(shù)將產(chǎn)生BUG。C++則不會(huì)產(chǎn)生這種類型的BUG。
  引用:千萬不要返回局部對象的引用。
  引用:千萬不要返回局部對象的指針。
  筆記:以上兩句是黑體的標(biāo)題:,書中專門進(jìn)行了討論。不過這個(gè)錯(cuò)誤雖然嚴(yán)重,卻不難理解。知道了就好了。
  main()是一個(gè)很特殊的函數(shù),它的特殊性在這里還有體現(xiàn)。引用:“返回類型不是void的函數(shù)必須返回一個(gè)值,但此規(guī)則有一個(gè)例外的情況:允許主函數(shù)main沒有返回值可結(jié)束?!幾g器會(huì)隱式地插入返回0的語句?!?br />?
標(biāo)題::傳遞數(shù)組的函數(shù)與字符串函數(shù)
如果將數(shù)組作為實(shí)參來調(diào)用函數(shù),函數(shù)接收到的形參其實(shí)是一個(gè)指針。數(shù)組名是可以轉(zhuǎn)換為指針的,但是數(shù)組名和指針畢竟不等價(jià)。所以,這樣傳遞的結(jié)果是丟失了數(shù)組原有的一些特性。最大的損失莫過于sizeof對數(shù)組大小的測試。試看以下程序:
void FuncA(int *temp)
{
  cout << sizeof(temp) << endl;
}
void FuncB(int temp[])
{
  cout << sizeof(temp) << endl;
}
void FuncC(int temp[20])
{
  cout << sizeof(temp) << endl;
}
int main()
{
  int a[10];
  cout << sizeof(a) << endl;
  FuncA(a);
  FuncB(a);
  FuncC(a);
  return 0;
}
  三個(gè)函數(shù)的寫法各有不同,但是結(jié)果卻是一樣的。其中FuncC的寫法尤其容易產(chǎn)生誤解。因?yàn)榫幾g器不管你傳遞的是多大的數(shù)組(甚至不管是不是數(shù)組),但是函數(shù)的寫法卻在暗示程序員這個(gè)數(shù)組有20個(gè)成員。如果實(shí)參成員超過20個(gè),結(jié)果就是沒有起到完全的作用,如果實(shí)參成員不到20,那就指針越界了。
  為避免這樣的尷尬,有時(shí)我們將指針與容量一起傳入函數(shù):“void FuncD(int temp[], _size_t Size);”,或者傳遞兩個(gè)指針:“void FuncE(int* Begin, int* End);”。這樣做當(dāng)然好,不過C++還有另一種辦法可以不用這么麻煩,那就是引用傳遞:“void FuncF(int (&temp)[10]);”。這樣的函數(shù)只允許將int[10]實(shí)參傳入,大小不符的數(shù)組或非數(shù)組的指針都無法傳入。這樣就保證了10這個(gè)值的正確性,連sizeof都省了。
  C語言的字符串處理函數(shù)大概是僅有的可以不受此約束的函數(shù)了。字符串就是字符數(shù)組,但是在傳遞字符數(shù)組時(shí),可以只傳指針而不管大小。因?yàn)镃語言中的字符串都是以NULL尾的。前陣子有人在論壇提問,問及字符串和字符指針的關(guān)系。回答是:C語言的字符串是用字符數(shù)組存放的,而處理則是借助于字符指針。但是,要能進(jìn)行這樣的操作,有兩個(gè)條件必須滿足:一是所有字符連續(xù)放置在以指針開頭的內(nèi)存中、不跳躍,二是有一個(gè)規(guī)定的結(jié)束符。int[]數(shù)組之所以不能這樣做,是因?yàn)榈诙€(gè)條件無法滿足。
?
標(biāo)題::函數(shù)的引用返回值
引用是給變量取一個(gè)別名,所以引用傳遞會(huì)直接進(jìn)行變量本身的傳遞。它的最大好處是可以把別處對變量的改變保留下來,第二好處是它提高了性能:如果函數(shù)的返回值是一個(gè)引用,那么,如上文所說,它會(huì)節(jié)約一組構(gòu)造、賦值和析構(gòu)過程。但是,函數(shù)返回引用往往會(huì)帶來一些意想不到的錯(cuò)誤:比如返回臨時(shí)變量的引用。
//一個(gè)錯(cuò)誤的函數(shù)
int &Max(int i, int j)
{
  return i>j ? i : j;
}
  以上函數(shù)的錯(cuò)誤在于,i和j在函數(shù)結(jié)束后會(huì)被釋放。對它們的引和也將失效。如果用這個(gè)返回值給別的變量賦值,將會(huì)獲得一個(gè)垃圾。VC++.Net會(huì)對以上return語句顯示警告。
  那么,如果返回一個(gè)全局變的引用呢?這當(dāng)然是可以的,但是,一來程序設(shè)計(jì)中不建議使用過多的全局變量,二來全局變量即使不返回也可以訪問。這樣做的唯一用途就是把函數(shù)做右值來給其它變量賦值。
int m;//全局變量
int &MaxByGlobal(int i, int j)
{
  return m = i>j ? i : j;
}
int a, b, c;
c = MaxByGlobal(a, b);//用法一、用返回值賦值
MaxByGlobal(a, b); c = m;//用法二、不用返回值賦值
  當(dāng)然,以上這個(gè)MaxByGlobal函數(shù)也不是一無是處,能用返回值來進(jìn)行賦值會(huì)給程序帶來更好的可讀性。只是這樣的函數(shù)設(shè)計(jì)本身不被建議。
  那么,函數(shù)返回引用用得最多的就是返回形參了。因?yàn)樾螀⒖梢杂靡脗鬟f,引用的形參不是函數(shù)內(nèi)部的局部變量,這樣做是可取的:
int &MaxByRef(int &i, int &j)
{
  return i>j ? i : j;
}
  上面這個(gè)函數(shù)和上文中的“int Max(int i, int j)”函數(shù)如此相似,但是它省去了三次構(gòu)造、賦值和析構(gòu)。
  另外一種用法就是在類的成員函數(shù)中返回類對象自身了,典型的是“operator +=”函數(shù)之類。
MyClass &MyClass::operator +=(const MyClass &other)
{
  //某些語句
  return *this;
}
  以上函數(shù)返回的是自身的引用。因?yàn)轭惖某蓡T函數(shù)也可以寫成全局函數(shù)“MyClass &operator +=(MyClass &Left, const MyClass &right)”,而且在類成員函數(shù)的調(diào)用中實(shí)際存在著this指針的傳遞。所以,以上這個(gè)函數(shù)依然可以看作返回了形參的引用。
  對于返回引用的函數(shù),還有一個(gè)好玩的現(xiàn)像。即返回值還可能可以被賦值。如“(a += b) = c;”這樣的形式。這種寫法明顯不倫不類,但是如果函數(shù)返回了非const的引用,這個(gè)表達(dá)式的確是合理的。所以,上面的“operator +=”函數(shù)還要修改一下,將返回值由“MyClass&”改為“const MyClass&”。
  返回引用并不是處處可用的,正如《引用傳遞的應(yīng)用范圍》中提到的一樣:不能用引用來傳遞臨時(shí)值。有時(shí)候我們的確要產(chǎn)生一個(gè)臨時(shí)對象并返回它,那就不能返回引用。典型的有“operator +”函數(shù):
const MyClass MyClass::operator +(const MyClass &other) const
{
  MyClass Temp;
  //某些語句
  return Temp;//這里只能返回對象,因?yàn)門emp必須是局部變量
}
?
標(biāo)題::函數(shù)的非引用返回值
函數(shù)最多可以返回一個(gè)值,也可以不返回任何值(也有“返回void”的說法)。之所以最多只能返回一個(gè)值,因?yàn)橹挥羞@樣才能在表達(dá)式中使用。比如“y=Sin(x);”,如果Sin函數(shù)返回多個(gè)值,這個(gè)表達(dá)式就失去了意義。之于為什么可以不返回任何值,經(jīng)歷過BASIC的人應(yīng)該更能理解。因?yàn)锽ASIC中把有返回值的程序段叫函數(shù),沒有返回值的程序段則叫做“子程序”。很顯然,“子程序”就是完成一個(gè)特定的功能后結(jié)束的程序段。
  函數(shù)的返回值沒有類型限制,可以是內(nèi)置類型變量,也可以是類對象。無論是內(nèi)置類型還是類對象,都有著一樣的規(guī)律。但是,這些規(guī)律在C++到來之前很少有人去理會(huì),畢竟內(nèi)置變量類型太復(fù)通,以至于程序員根本不去考慮那么多“為什么”。
  在C時(shí)代,所有的返回值都是局部變量。如下列程序:
//程序一:
int Max(int i, int j)
{
  return i>j ? i : j;
}
//程序二:
char *StrCpy(char *Target, const char *Source)
{
  char *Temp=Target;
  while(*Source)
  {
    *Temp++ = *Source++;
  }
  return Target;
}
  程序二給人一個(gè)錯(cuò)覺:認(rèn)為該函數(shù)返回的不是函數(shù)內(nèi)部的局部變量。錯(cuò)誤原因在于沒有理解指針的本質(zhì)。其實(shí)程序二和程序一一樣,返回值是形參之一。而形參就是作用域?yàn)楹瘮?shù)內(nèi)部的局部變量。
  理解了“返回值是局部變量”還不夠。因?yàn)檫€有一個(gè)很重要的概念沒弄清。比如:
int a, b, c;
char d[10], e[10], *f;
//其它語句
c = Max(a, b);//語句一
f = StrCpy(d, e);//語句二
  以上注釋的兩行語句都有同一個(gè)問題:如果返回的變量作用域僅限于函數(shù)內(nèi)部,那么函數(shù)結(jié)束以后該變量就已經(jīng)不存在了,那么給c和f賦值的是什么?
  C和C++有一個(gè)機(jī)制保證以上賦值正常進(jìn)行:在函數(shù)結(jié)束前,先將要返回的局部變量臨時(shí)拷貝一份到棧內(nèi)存(這個(gè)內(nèi)存程序員無須知道,也無法知道)。然后將局部變量銷毀,函數(shù)正常結(jié)束。接下來用棧中的臨時(shí)變量對目標(biāo)變量進(jìn)行賦值,賦值結(jié)束后再把臨時(shí)變量銷毀。
  以上這個(gè)過程憑空多出一次變量構(gòu)造、復(fù)制與銷毀過程,好在對于內(nèi)置類型變量來說,這樣的過程所需的性能賦出并不太多。但是C++到來以后,函數(shù)的返回值類型可以是類類型。而類對象的構(gòu)造、復(fù)制與銷毀可能很復(fù)雜、很占用系統(tǒng)資源。于是“引用傳遞”再一次發(fā)揮了它的威力。
?
標(biāo)題::引用傳遞的應(yīng)用范圍
經(jīng)過三篇文章的細(xì)述,函數(shù)的參數(shù)傳遞應(yīng)該比較明朗了,經(jīng)過一番對比,似乎引用傳遞是最優(yōu)秀的一種傳遞方式。第一、它用法很簡單,類似于值傳遞,第二、它功能很強(qiáng)大,類似于指針傳遞,第三、它很安全,可以避免指針傳遞帶來的危險(xiǎn),第四、它效率高,函數(shù)中不必要進(jìn)行對象的創(chuàng)建、賦值與釋放。第五、如果不希望實(shí)參被改變,可以使用const修飾形參……
  但是,天下沒有這么便宜的午餐!引用傳遞不是倒處能用的。舉個(gè)例子:
void Swap(int& a, int& b)
{
  int temp = a;
  a = b;
  b = temp;
}
  以上函數(shù)可以進(jìn)行兩個(gè)int變量的交換。但是,很多情況下該函數(shù)不能調(diào)用:
int ia = ib = 1;
short sa = sb = 2;
const int cia = cib = 3;
Swap(ia, ib);//正確
Swap(sa, sb);//錯(cuò)誤,short不是int,雖然可以隱式轉(zhuǎn)換為int,但是這個(gè)變量不存在
Swap(cia, cib);//錯(cuò)誤,這兩個(gè)參數(shù)是const的
Swap(4, 5);//常量不是變量,類似于將short變量傳遞給函數(shù)
Swap(ia+ib, ia-ib);//錯(cuò)誤,表達(dá)式求值后產(chǎn)生的臨時(shí)值不是變量
  其中將const參數(shù)傳遞進(jìn)函數(shù)的做法,雖然看起來有些荒誕,實(shí)際上某些時(shí)候會(huì)不經(jīng)意間做的。某個(gè)變量在定義的時(shí)候并不是const的,但是在調(diào)用某個(gè)函數(shù)的時(shí)候?qū)⑺鳛閏onst形參傳入,而該函數(shù)內(nèi)部再調(diào)用Swap()函數(shù)時(shí),這個(gè)變量已經(jīng)成了局部的const變量。
  以上這個(gè)特性反過來應(yīng)用是很有用的。在多人協(xié)作寫程序的時(shí)候,或者寫一個(gè)大型程序的時(shí)候。你不知道某函數(shù)是否用const來保護(hù)參數(shù),但是你想保護(hù)參數(shù)。那么,你就在自己寫的原調(diào)函數(shù)中將該參數(shù)保護(hù)起來。這樣,當(dāng)你調(diào)用某個(gè)沒有顯式指定const引用參數(shù)的函數(shù)時(shí),編譯器就會(huì)報(bào)錯(cuò)。
void funca(const int& a)
{
  funcb(a);//發(fā)生錯(cuò)誤
}
void funcb(int& b)
{
  ...;
}
int t;
funca(t);
以上程序會(huì)在注釋的那行停止編譯。因?yàn)樵谒{(diào)用了函數(shù)b,而b沒有聲明參數(shù)為const。雖然函數(shù)b中未必改動(dòng)參數(shù)。
?
?
標(biāo)題::形參與實(shí)參的關(guān)系之引用傳遞
C++有了“引用傳遞”后,“形參的改變不影響實(shí)參”被判無效。因?yàn)閭鬟f給函數(shù)的并不是一個(gè)值,而是變量自身。在函數(shù)中定義的形參雖然還是局部變量,但卻是一個(gè)引用。雖然這個(gè)引用的作用域僅限于函數(shù)內(nèi)部,但是由于它與實(shí)參就是同一回事,所以對它的操作完全等同于對實(shí)參的操作。比如你叫“黑旋風(fēng)”去買魚,或者叫“鐵?!比ベI魚,去的都是同一個(gè)人。
  C++為什么要有“引用傳遞”這回事?一種說法是只有引用才能達(dá)到操作符重載的目的,這個(gè)以后再談。但是,撇開這個(gè)不談,形參是不是引用,直接影響了程序執(zhí)行的效率。前面提到過,函數(shù)調(diào)用時(shí)要用實(shí)參的值去初始化形參,初始化的過程包含了定義一個(gè)變量、然后給它賦一個(gè)值兩個(gè)過程,如果這個(gè)變量并不是內(nèi)部變量,而是一個(gè)類對象,那么,定義一個(gè)類對象可能很復(fù)雜,而初始化這個(gè)對象一樣會(huì)很復(fù)雜。而引用只是給對象取一個(gè)別名,不涉及定義與初始化,離開作用域時(shí)也不用釋放。
  相比之下,用指針傳遞可以避免類對象的定義、初始化與釋放。只需要付出指針變量的定義、初始化與釋放的代價(jià)。但是,指針的殺傷力太大。即使是熟練的程序員,也不能保證絕不出現(xiàn)“野指針”,野針的代價(jià)幾乎無一例外是程序崩潰。
  引用也不是吃素的,如果說指針傳遞是“幫你配了一把我家的鑰匙”,那么引用傳遞就是直接把我家的財(cái)產(chǎn)都交給了你。有時(shí),我們使用引用傳遞僅僅是為了效率,而不希望實(shí)參被修改,那就要記得把形參標(biāo)記為const,如“UINT GetLength(const CString&)”。
  順便說一句,指針傳遞也可以這樣做。把形參定義為指向const對象的指針(而不是const指針),可以降低殺傷力,保護(hù)實(shí)參所對應(yīng)的內(nèi)存。如果是普通的值傳遞,那么有沒有const對函數(shù)外部并不影響。但是,我個(gè)人認(rèn)為,有時(shí)候加上const也是一件好事。如果程序的邏輯并不需要改變參數(shù),而實(shí)際上誤寫了代碼,加上const可以讓編譯器幫我們找出BUG,如:
int Max(const int a, const int b)
{
  return a>b?a:b;
}
  VB沒有指針的概念,卻有“值傳遞”和“地址傳遞”兩個(gè)概念。比如“Function Func(ByRef i As Integer) As Integer”,變量i接受了實(shí)參后,它的改變能影響實(shí)參。它的實(shí)質(zhì)就類似于C++中的引用傳遞。
?
?
標(biāo)題::形參與實(shí)參的相互關(guān)系
“形參的改變不影響實(shí)參”這句話說起來輕巧,但是要完全理解,似乎還有幾個(gè)玄機(jī)。
  在我發(fā)表《函數(shù)的定義》一文后,有朋友發(fā)表意見,提到了“函數(shù)調(diào)用過程中的入棧與出?!?#xff0c;在此首先作個(gè)說明:我讀的是《C++ Primer》,而不是《編譯原理》,入棧與出棧不歸我討論。在現(xiàn)在討論的尺度內(nèi),我們可以這么認(rèn)為:形參是函數(shù)內(nèi)部的一個(gè)局部變量,該局部變量在函數(shù)開始執(zhí)行時(shí)被初始化,而初始化它的值則來自實(shí)參的值。也就是說,它的定義與初始化類似于“int i=3;”。只是被分成兩行寫了,形參的定義寫在函數(shù)的定義中,如:“int ttt(int b)”,初始化寫在了調(diào)用中“cout << ttt(a) << endl;”?!獏⒖瓷弦黄恼隆缎螀⑴c實(shí)參概念》。
  那么,在函數(shù)中無論怎樣改動(dòng)b的值,被改的始終是形參這個(gè)局部變量,函數(shù)結(jié)束時(shí),離開這個(gè)局部變量的作用域,變量被釋放。
  但是,C語言的“指針傳遞”總是給人“形參能改變實(shí)參”的感覺,其實(shí)這是一個(gè)誤解。對于指針傳遞來說,函數(shù)的形參是一個(gè)指針,傳給它的實(shí)參也應(yīng)該是指針(或者能轉(zhuǎn)為指針的值,比如數(shù)組名、能轉(zhuǎn)換為指針的類等)。在函數(shù)中,如果改變了該指針(對指針的改變就等同于讓這個(gè)指針指向別處),不會(huì)影響主調(diào)函數(shù)中的實(shí)參。但是,由于指針對應(yīng)著一個(gè)內(nèi)存地址,通過它可以改變內(nèi)存的內(nèi)容。所以,無論在函數(shù)內(nèi)部的形參還是外部的實(shí)參,它們都可以影響同一內(nèi)存的值。所以,指針傳遞可以把函數(shù)內(nèi)部的影響帶到函數(shù)外,但是,帶到函數(shù)外的絕不是形參,而是形參所指的內(nèi)存。
  這就好比我把我家的鑰匙給你配了一把,我手里的鑰匙是實(shí)參,你手里的鑰匙是形參。你無論是把鑰匙折斷還是磨短,都與我的鑰匙無關(guān),但是你用它開了我家的門卻可以把我家洗劫一空。你影響的不是我的鑰匙,而是我的財(cái)產(chǎn)。
  上文說到,C++有了“引用傳遞”后,“形參的改變不影響實(shí)參”被判無效。這就得提到“引用傳遞”的概念了,下文再續(xù)。
對本文本的評論有:
簡單地說,每次調(diào)用函數(shù)的時(shí)候,形參把實(shí)參克隆了一次,你再怎么折騰形參,也與實(shí)參無關(guān).
TNND就是一個(gè)入棧與出棧過程嘛,你可以去學(xué)學(xué)匯編.
舉例:
mov cs1,100 //cs1=100;
push cs1 //把cs1入棧;
pop cs2 //把棧中的內(nèi)容出棧給cs2;
這與另一句話等價(jià):
mov cs1,100
mov cs2,cs1
為什么會(huì)使用上面的那種用法呢?
因?yàn)閜ush和pop占用更少的CPU周期.所以,一般調(diào)用函數(shù)都用入/出棧來備拷貝參數(shù).
?
?
?
標(biāo)題::形參與實(shí)參概念
說到形參與實(shí)參,在C++出來之前其實(shí)很簡單,就一句話:形參的改變不影響實(shí)參。這個(gè)狀態(tài)直到C++有了“引用傳遞”才有改變。
  要弄清這個(gè),首先得弄清形參與實(shí)參是什么東西。因?yàn)楹瘮?shù)是一段“可以重用而不必重寫”的代碼,每次重用當(dāng)然未必完全相同(不可否認(rèn)有些函數(shù)每次重用都完全相同),那么不同在哪里呢?又怎樣產(chǎn)生不同呢?一種方法是依靠隨機(jī),隨機(jī)是個(gè)好東西,不要說客戶了,連程序員都無法控制每次調(diào)用的結(jié)果。第二種方法是憑客觀條件(比如運(yùn)行時(shí)間、機(jī)器配置)。但是這些函數(shù)應(yīng)用很窄,類似于“y=Sin(x)”這樣的函數(shù)就絕不能這樣做。
  那么,從“y=sin(x)”的形式看來,能決定函數(shù)怎樣運(yùn)行的唯一因素就是x的值了。函數(shù)的某次運(yùn)行是受某一個(gè)x值的影響并控制的,而下一次運(yùn)行,則會(huì)受另一個(gè)x值的影響。那么,調(diào)用函數(shù)者就有必要告訴函數(shù):我要用哪個(gè)值來控制你,而函數(shù)自己則有必要保存這個(gè)值,直到函數(shù)結(jié)束。
  為此,在函數(shù)內(nèi)部建立一個(gè)臨時(shí)的、局部的變量,該變量的作用域就是函數(shù)內(nèi)部,該變量的作用時(shí)間就是從函數(shù)開始執(zhí)行到結(jié)束執(zhí)行。如果同一函數(shù)在同一時(shí)間有幾個(gè)副本在執(zhí)行(這種情況在多線程程序中會(huì)出現(xiàn)),那么它們是互不相干的,它們內(nèi)部的變量也是互不相干的。這個(gè)變量就叫做“形參”,全稱形式參數(shù)。
  “形式”是跟“實(shí)際”相對的,另一個(gè)參數(shù)就是實(shí)際參數(shù),叫“實(shí)參”,在調(diào)用函數(shù)時(shí),這個(gè)值將決定函數(shù)內(nèi)部的形參的值。實(shí)參在函數(shù)中是否可見?這要取決于兩個(gè)因素:一是實(shí)參的作用域,二是有沒有被形參覆蓋。先說第一個(gè)因素,如果只談C語言,那么所謂的作用域就是全局與局部兩種,但是C++中還有“類作用域”這一概念,由此第一個(gè)因素變得復(fù)雜了。第二個(gè)因素本身并不復(fù)雜,但是如果沒有引起程序員的注意,那么造成的問題是很難發(fā)現(xiàn)的。試看下以下程序:
int a;//全局變量
int ttt(int a)//該函數(shù)的形參也叫a
{
  cout << ++a << endl;
  return a;
}
int main()
{
  a = 3;
  cout << a << endl;
  cout<< ttt(a) << endl;
  cout << a << endl;
  return 0;
}
  該程序中有一個(gè)全局的a變量,但是在ttt()函數(shù)中卻被另一個(gè)a覆蓋了,所以,++a沒有影響到全局的a,如果把函數(shù)定義改為“int ttt(int b)”則有不同的結(jié)果。
  以上把“形參”和“實(shí)參”提了這么多,主要目的還是講清“形參的改變不影響實(shí)參”這句話。字?jǐn)?shù)不少了,留到下篇文章再續(xù)吧。(我覺得我寫得不像讀書筆記,倒像是教材了。呵呵)
?
標(biāo)題::函數(shù)的定義
不記得在哪本書上看到過,函數(shù)的定義為“有名稱的一段代碼”。這大概地說明了函數(shù)的實(shí)質(zhì):首先、它是一段代碼,其次、這段代碼可以被重復(fù)使用而不必重復(fù)編寫,第三、它是有名字的,在需要重用的時(shí)候憑名字來調(diào)用。
  這個(gè)說法到了C++中變得復(fù)雜了。原因之一是C++支持函數(shù)重載,也就是說出現(xiàn)了同名函數(shù)。雖然編譯器在編譯時(shí)產(chǎn)生不同的函數(shù)名,但那必竟是編譯器的事,對于程序員來說就是同一個(gè)函數(shù)名。原因之二是C++支持運(yùn)算符重載,可以用一個(gè)類似于“+”號的運(yùn)算符來調(diào)用函數(shù)。運(yùn)算符重載明擺著是為了配合類對象的運(yùn)算,因?yàn)槿绻麤]有類,僅針對內(nèi)置類型,運(yùn)算符是沒必要重載的?!以囼?yàn)了一下,自定義了一個(gè)“int operator +(int i, int j)”函數(shù),結(jié)果沒有通過編譯。
  于是,到了C++中,函數(shù)的概念被修改為“函數(shù)由函數(shù)名以及一組操作數(shù)類型唯一地表示”,依我看,這樣說還不夠。嚴(yán)格說來,應(yīng)該說“函數(shù)由作用域、函數(shù)名以及一組操作數(shù)類型唯一地表示”,理由很簡單,因?yàn)樵诓煌淖饔糜蛑锌梢猿霈F(xiàn)名稱相同、參數(shù)類型也相同的函數(shù),除非把“作用域::函數(shù)名”合起來看作一個(gè)函數(shù)名。
  函數(shù)對函數(shù)體沒有任何強(qiáng)制性要求,哪怕函數(shù)體為空也可以。不過,無論是空、一句語名,還是多句語句,花括號一定不可少。在這里,包括在花括號內(nèi)的若干行語句不能再視為一個(gè)復(fù)合語句了——因?yàn)槟芊艔?fù)合語句的地方也能放簡單語句,而簡單語句可以不使用花括號。
  不管你如何看待這組花括號,有一點(diǎn)是肯定的:花括號內(nèi)部是一個(gè)作用域。那么,內(nèi)部定義的變量就只有在內(nèi)部使用了。這就是局部變量,在任何函數(shù)(包括main())內(nèi)部定義的變量都是局部變量——初學(xué)者可能以為在main()內(nèi)部定義的變量是全局變量。
  有一種內(nèi)部變量的定義與以往的定義方式不一樣,那就是函數(shù)的參數(shù)。不同之處在于:一是它們用逗號分隔,二是不允許用“int i,j”這樣的方式定義一組變量。我想,也許正是因?yàn)樗卸x用逗號分隔,才造成不允許后者的吧,畢竟這樣會(huì)帶來歧義——j沒有指定類型。如果用分號來分隔,那么后者的方式也許就可以了。這是C++標(biāo)準(zhǔn)的事,我沒有能力來為標(biāo)準(zhǔn)出謀劃策,只能妄加猜測了。
  函數(shù)的返回值也是一個(gè)類型,與變量的類型一樣,它可以是內(nèi)置類型,也可以是類類型,還可以是引用和指針。
  引用:在C++標(biāo)準(zhǔn)化之前,如果缺少顯式返回類型,函數(shù)的返回值將被假定為int型。
  筆記:據(jù)我測試,在VC++.NET中,這樣做是可以的。照這么說,VC++.NET仍然沒有按照C++標(biāo)準(zhǔn)做?或者說VC++.NET遷就了老程序員?
對本文本的評論有:
函數(shù)的參數(shù)當(dāng)然不能使用類似int i,j的方式,因?yàn)檎{(diào)用函數(shù)的時(shí)候,涉及到的不僅僅是定義參數(shù),還有把要處理的變量入棧,調(diào)用的函數(shù)運(yùn)行前的第一件事,是把被入棧的變量出棧.
這與int i,j定義變量做的事完全不同,所以,不按定義變量的方式寫,也很正常.
如果偷貓兄一定要寫得一樣,那就自己做一個(gè)編譯器吧.
?
標(biāo)題::函數(shù)概念
進(jìn)入第七章學(xué)習(xí)。
  “函數(shù)”這個(gè)概念在C/C++里頭是很煩人的。原因在于,好多C語言入門書的第一章第一節(jié)都說“C語言是由函數(shù)組成的”,初學(xué)者學(xué)到這里,就好像是剛推開C的大門就被一個(gè)麻袋套在頭上,什么也看不見了。那些書本還舉了一個(gè)例子,然后對照著例子說“這個(gè)程序是由main()、scanf()、printf()函數(shù)組成的……”。我暈啊,初學(xué)者第一天上C的課,哪里會(huì)管什么函數(shù)不函數(shù)的。
  這點(diǎn)BASIC做得不錯(cuò),倒不是說BASIC比C++好,而是BASIC容易入門。在開頭幾節(jié)課不必理會(huì)這么復(fù)雜的東西,學(xué)了“Let語句”、“Print語句”就可以涉足簡單的算法了。然后提到的“函數(shù)”是包括數(shù)學(xué)函數(shù)在內(nèi)的“內(nèi)部函數(shù)”。我們在數(shù)學(xué)里學(xué)過“函數(shù)”概念,知道“y=Sin(x)”是一個(gè)函數(shù),現(xiàn)在在BASIC里學(xué)到一樣的函數(shù),自然容易入門。等這一切都熟悉了,再去學(xué)習(xí)自己寫的函數(shù)——自定義函數(shù),會(huì)更加理解程序中的“函數(shù)”概念。
  VB與早期的BASIC相比,使用了“事件驅(qū)動(dòng)”原理。畫完界面就得面對函數(shù)了,但是VB用“事件”這個(gè)說法來回避了。初學(xué)者可以不知道“Private Sub Command1_Click()”究竟代表什么,只要知道那是“按鈕控件被單擊后執(zhí)行的代碼”就夠了。等到后來,學(xué)習(xí)了“自定義函數(shù)”后,必然會(huì)恍然大悟。
  回到C++中,學(xué)習(xí)之初用到的函數(shù)的確是現(xiàn)成的庫函數(shù),但是正因?yàn)檫^早地提到了函數(shù)概念,導(dǎo)致了初學(xué)者無所適從。有沒有別的辦法呢?當(dāng)然有了,至少《C++ Primer》這本書一直到第七章才開始提“函數(shù)”二字。
  另外:VB中有“函數(shù)”和“子程序”兩個(gè)不同的概念,如今“子程序”又叫“過程”,除了使用不同的關(guān)鍵字以外,它們的惟一區(qū)別是有沒有返回值。C將它們合并了,都叫函數(shù)。其實(shí),VB里的函數(shù)也可以丟棄返回值,只是VB里沒有與“void”對應(yīng)的詞,無法定義不返值的函數(shù),才不得已出此下策。
?
?
標(biāo)題::try、catch和assert
程序員是要慢慢成長的,比如錯(cuò)誤處理這種事情,就不是一開始就面對的。當(dāng)我們編的程序還很小,小到“cin>>i; cout<<i;”這樣的程度,錯(cuò)誤處理不是我們要學(xué)習(xí)的目標(biāo)。但是,一旦開始編寫實(shí)用的程序,那么,無論考慮多么周到,無論代碼多么精良。意外總是難免的。這些意外可能來自程序員的設(shè)計(jì)不到位、可能來自用戶的錯(cuò)誤操作、還可能來自機(jī)器與網(wǎng)絡(luò)的不確定因素。
  沒有什么比追蹤錯(cuò)誤更難過的事了,記得有一回我在追蹤一個(gè)VB程序的錯(cuò)誤。經(jīng)過長時(shí)間測試,我發(fā)現(xiàn)程序在運(yùn)行中突然發(fā)生很大的跳躍:函數(shù)A調(diào)用B,B調(diào)用C,在C的執(zhí)行過程中,居然會(huì)突然跳到A中。后來追查發(fā)現(xiàn),原來A中有一行“On Error Goto”語句。這一個(gè)語句,影響了我調(diào)試C函數(shù)。從那以后,我明白了,除非程序要發(fā)布了,否則別啟動(dòng)錯(cuò)誤處理。
  C++與VB不一樣,VB用一句“On Error Goto”啟動(dòng)了錯(cuò)誤處理后,在該函數(shù)結(jié)束之前一直有效(除非顯式地關(guān)閉它)。如果發(fā)生了異常,處理代碼要根據(jù)異常的值來分析異常的類型。而C++可以選擇可能出現(xiàn)異常的內(nèi)容放進(jìn)try后的塊中。一個(gè)函數(shù)內(nèi)部可以有多個(gè)try塊,而每個(gè)try塊又可以附帶多個(gè)catch來處理。應(yīng)該說,C++中的異常處理更靈活,當(dāng)然也更容易出錯(cuò)。我前陣子發(fā)生的錯(cuò)誤就是在ADO處理后只有“catch(_com_error *e)”,但是實(shí)際上出現(xiàn)的異常卻不是“_com_error”類的,結(jié)果仍然抓不往異常。
  異常處理和assert之間的關(guān)系有些讓人難以捉摸。一方面它們各有各的作用,另一方面它們有時(shí)會(huì)互相影響。我就曾經(jīng)在這上面吃過虧:我的程序是在服務(wù)器上運(yùn)行的,從來沒人會(huì)盯著服務(wù)器看,所以我的程序不允許彈出對話框。我寫了比較完善的異常處理,無論出現(xiàn)什么錯(cuò)誤,都記錄進(jìn)LOG文件,然后繼續(xù)運(yùn)行。但是我卻是用DEBUG模式編譯的,結(jié)果異常到來時(shí),try沒起作用,倒是assert起作用了,彈了個(gè)對話框在那兒。這件事給我的啟發(fā)是:別以為自己是程序的客戶就可以用DEBUG模式編譯。
對本文本的評論有:
錯(cuò)誤捕捉是很煩人,我的感覺是能在try代碼段外解決的錯(cuò)誤,就盡量在外頭自己解決,盡量少依靠try來處理捕獲錯(cuò)誤.
在網(wǎng)絡(luò)編程中,有些錯(cuò)誤是無法預(yù)知的,比如網(wǎng)絡(luò)連接斷了,數(shù)據(jù)庫當(dāng)了...好象在這些情況下,用try比較好.
我有一次寫的一個(gè)服務(wù)程序,用戶用了一段時(shí)間后,經(jīng)常會(huì)異常中止,查來查去查不出原因,后來才發(fā)現(xiàn)是ORACLE的日志滿了,這個(gè)錯(cuò)誤顯然我在寫程序的時(shí)候沒有想過,丟臉啊...
?
標(biāo)題::break、continue和goto
break和continue的使用范圍比較一致,兩都可以用于循環(huán),其中break還可以用于switch。功能上也有一定的相似性,break就相當(dāng)于退學(xué),continue則相當(dāng)于跳級。對于break,程序究竟跳到哪兒比較好理解。但是continue究竟跳到哪兒去了,初學(xué)者可能有些疑惑,不妨就當(dāng)它跳到了循環(huán)體最后一句語句的后面。
  如果它們處在由多重循環(huán)和switch組成的圈圈里,那么它們就對包括它們的最里層起作用。于是,設(shè)想一下子跳出多重循環(huán)的人可能忘不了goto。
  引用:從上世紀(jì)60年代后期開始,不主張使用goto語句。……所有使用goto的程序都可以改寫成不用goto。
  筆記:goto是一個(gè)很有爭議的語句,語多書本建議少用或不用它,我個(gè)人的習(xí)慣是堅(jiān)決不用。不過,至于“上世紀(jì)60年代”這個(gè)說法,我倒是一直不知道。因?yàn)槲易约簩W(xué)習(xí)BASIC已經(jīng)是1994年,那時(shí)候?qū)W的是帶行號的GW-BASIC,goto是必須用到的語句。莫非當(dāng)時(shí)我們學(xué)校開設(shè)的課程居然是落后二十年的內(nèi)容?
  林銳博士對goto另有看法,他說:“錯(cuò)誤是程序員自己造成的,不是goto的過錯(cuò)。goto至少有一處可顯神通,它能從多重循環(huán)中咻地一下子跳到外面,……就像房子著火了,來不及從樓梯一級一級往下走,可從窗口跳出火坑?!?#xff08;《高質(zhì)量C++/C編程指南》第32頁)
  我寫的程序目前還沒有超越三級循環(huán)。從最里層往外跳,如果跳一層,就break,如果跳兩層或三層,一是這種可能性很小,二是如果真的碰到了,我就用其它條件來控制外層循環(huán)是否繼續(xù)break,自從1997年進(jìn)入結(jié)構(gòu)化的程序設(shè)計(jì)以來,我的確完全拋棄了goto。——VB中的“On Error Goto”除外,出現(xiàn)錯(cuò)誤,自然不管在哪一層,都給我跳進(jìn)錯(cuò)誤處理中。
  goto的目標(biāo)是一個(gè)標(biāo)號,這個(gè)標(biāo)號的起名倒有點(diǎn)意思,因?yàn)闃?biāo)號只用于goto,所以它的名字可以與任何變量名以及其它標(biāo)識符一樣而不產(chǎn)生重名。以前的程序是帶行號的,所以就“goto 行號”,現(xiàn)在程序不帶行號了,但是允許在任何地方加標(biāo)號。編譯器在碰到它們的時(shí)候,大概就是憑其后頭的冒號來判斷這個(gè)名字不需要檢驗(yàn)合法性。那么,C++中已有的“public:”算不算標(biāo)號呢?
  為此,我做了個(gè)實(shí)驗(yàn):實(shí)驗(yàn)內(nèi)容一是我在類的聲明里加入了一行“pub:”,二是我在程序段中加入了一行“public:”。結(jié)果發(fā)現(xiàn)兩都都不能通過編譯。也就是說,實(shí)驗(yàn)一說明在類定義這樣的地方不允許使用標(biāo)號(也用不著,因?yàn)樗辉谌魏魏瘮?shù)內(nèi)部,goto是運(yùn)行時(shí)的事,與編譯無關(guān),而且goto不允許跨函數(shù)跳越。),實(shí)驗(yàn)二說明在程序段中的標(biāo)號不允許使用保留字。
對本文本的評論有:
不主張使用GOTO語句是為了讓程序看起來順眼而己.看:模塊化的代碼.其實(shí)的確沒什么大不了的.記住,當(dāng)你的程序被編譯成機(jī)器代碼以后,里面的跳轉(zhuǎn)全是JMP,相當(dāng)于GOTO.
?
自從和草莓對罵以來,你就學(xué)會(huì)了狡辯。
我有跟你討論機(jī)器碼嗎?
程序設(shè)計(jì)的風(fēng)格是為了程序維護(hù),
不是為了編譯。
?
標(biāo)題::while、for語句
while中有一個(gè)怪事:類似于“while (int i = GetInt())”這樣的語句,在條件中定義一個(gè)變量,在for中非常常見,也很好理解。但是用在while中卻有所不同,如果用在while中,那么每次循環(huán)都會(huì)經(jīng)歷一次創(chuàng)建和撤銷的過程?!?#xff0c;還是不要這樣寫吧。幸虧我總是在while前面定義并初始化變量的。
  do-while與while有著不一般的關(guān)系,所以幾乎所有的書本都是把它們放一起講的。當(dāng)年學(xué)BASIC時(shí),花了不少的功夫去學(xué)習(xí)“當(dāng)型循環(huán)”和“直到型循環(huán)”。的確,當(dāng)型和直到型都有存在的必要,因?yàn)槌绦虻拇_有這兩種邏輯需要。于是C、BASIC以及PASCAL等程序語言都提供了這兩種循環(huán)。不過提供歸提供,怎么用卻是程序員自己的事。就我個(gè)人而言,我還是喜歡用當(dāng)型循環(huán)。因?yàn)楫?dāng)型循環(huán)可以模擬出直到型循環(huán)的效果來。比如以下四段代碼,它們是完全一致的:
//代碼1
do
{
  循環(huán)體;
  BoolVal = 表達(dá)式;
}while (BoolVal);
//代碼2
BoolVal = 1;//先賦True值
while(BoolVal)
{
  循環(huán)體;
  BoolVal = 表達(dá)式;
}
//代碼3
do
{
  循環(huán)體;
}while (表達(dá)式)
//代碼4
while(1)
{
  循環(huán)體;
  if (!表達(dá)式) break;
}
  for語句的執(zhí)行順序和執(zhí)行邏輯是最難講清的了。如果知道了,就是這么回事。如果不知道,不費(fèi)上半天口舌是說不清的。原因在于for包括四個(gè)互相關(guān)聯(lián)的語句,其中三個(gè)在“for”后面的括號里,另一個(gè)作為循環(huán)體存在。這也難怪BASIC要將for語句定義為“For i=M To N Step t”的格式。
  for括號里的三個(gè)語句是可以省略的,最牛B的省略莫過于“for (;;)”了。會(huì)這樣寫的人,要么是徹徹底底地明白了for的邏輯的人,要么是一點(diǎn)不懂的人。我覺得,如果要我這樣寫,我不如寫“while(1)”了。
?
?
標(biāo)題::if、switch語句
本書不愧為經(jīng)典書,在if這地方能避免說教,講得繪聲繪色,真叫人佩服。
  大體上if要注意的就只有else的配對問題了。如果在else前方有多個(gè)沒有配對的if,那就找最近的一個(gè)配對。如果要改變這種默認(rèn)的“拉郎配”,就加上花括號。
  還是引用林銳博士的一句話吧:“if、for、while、do等……不論執(zhí)行語句有多少都要加{}。這樣可以防止書寫失誤?!?#xff08;《高質(zhì)量C++/C編程指南》第16頁)
  if語句曾有一個(gè)令我疑惑了好久的東西:“else if”究竟算什么?因?yàn)锽ASIC里有“ElseIf”這個(gè)關(guān)鍵詞,而C++中所謂的“else if”是兩個(gè)關(guān)健詞組成的。中間插了個(gè)空格。我們都知道,C++的語句與語句之間插入若干個(gè)(包括0個(gè))空格、TAB、回車都是一樣的,那么,如果我把else后插入一個(gè)回車,不成了另一種結(jié)構(gòu)的if語句了么?后來我仔細(xì)地分析一下邏輯關(guān)系,才豁然開朗:原來是BASIC的“ElseIf”干擾了我的理解。C++中用哪種方法去理解都沒區(qū)別。
  都說switch是為了簡化if而出現(xiàn)的,但是switch雖然可以簡化if,卻并不是任何時(shí)候都能使用。使用switch有兩個(gè)先決因素:一是所有的條件都必須是編譯時(shí)常量。也就是說如果要在程序運(yùn)行時(shí)再?zèng)Q定case后的條件,那是不行的。另一個(gè)因素是只能拿出若干個(gè)整數(shù)值來比較是否相等,既不能是浮點(diǎn)數(shù),也不能比較大于或小于。
  switch最容易出錯(cuò)的就是丟失break語句了。因?yàn)榘闯R?guī)思路,人們總以為兩個(gè)標(biāo)號之間的語句才是應(yīng)該執(zhí)行的。從BASIC過來的人更加痛苦,因?yàn)锽ASIC里不需要類似于break這樣的語句來表示結(jié)束。
  我的做法是,在打程序框架時(shí),先把case標(biāo)號和break寫了,其余的再去完善。即使邏輯上不需要break語句,也要寫上“//break;”,這樣可以提醒自己和團(tuán)隊(duì)的伙伴:此處并未丟失break,而是的確不需要。
  丟失default是最理直氣壯的了。因?yàn)榈拇_有許多時(shí)候并不需要default,但是我的經(jīng)驗(yàn)是要加上default以及它后面的break,原因同上,提醒自己和伙伴我沒有遺漏。
?
標(biāo)題::簡單語句與復(fù)合語句
祝賀進(jìn)入第6章的學(xué)習(xí)。
  簡單語句就是只有一句的語句,“復(fù)合語句”也叫語句塊,是由多句語句組成的一個(gè)整體。雖然BASIC也有語句塊的概念,但是它們卻是不同的概念:BASIC將簡單語句視為特殊的語句塊,而C++則將語句塊視為特殊的簡單語句。個(gè)人認(rèn)為,C++中復(fù)合語句的存在是為了補(bǔ)充C++沒有“end if”之類語句的缺陷。
  BASIC中,if有end if(行if除外)、while有wend,do有l(wèi)oop。也就是說,有頭就有尾,所以,BASIC編譯器不擔(dān)心無法確定語句塊的大小。C++則不同,它的這些關(guān)鍵字都沒有結(jié)束語句。沒有結(jié)束標(biāo)記,誰知道它的主體究竟是幾行呢?所以,C++只好規(guī)定:所有這些結(jié)構(gòu)的語句體都只能包含一句,而且必須包含一句(有且僅有一句)。換句話說,如果要多句,你也得做成一句的樣。
  將多行做成一行,就是所謂的“復(fù)合語句”了。
  說到簡單語句,空語句和空塊是不能不提的。空語句(塊)也是語句(塊),只是它啥也不干??照Z句存在的原因,無非也是因?yàn)镃++中規(guī)定了語句體必須是一句。剛才說了,那些結(jié)構(gòu)的語句體是“有且僅有一句”,不僅僅“多于一句要寫成一句的樣”,反過來說,如果沒有任何內(nèi)容,你也得偽造一句出來。于是“空語句”問世了。
  以下語句就是一個(gè)典型的例子:
int s = 0;
for (int i=1,s=0; i<101; s+=i,++i) ;//空語句
  空語句的存在為C++徒增了難度與危險(xiǎn)性,很多初學(xué)者弄不清哪些語句要以分號結(jié)尾,哪些語句不要,錯(cuò)誤地在for()后面加了個(gè)分號,結(jié)果使循環(huán)體被取消了循環(huán)的資格,而且有可能出現(xiàn)死循環(huán)。
?
?
標(biāo)題::顯式轉(zhuǎn)換
引用:顯式轉(zhuǎn)換也稱為強(qiáng)制類型轉(zhuǎn)換。
  筆記:我覺得要提強(qiáng)制類型轉(zhuǎn)換,得從C風(fēng)格的說起。這里面可能有我個(gè)人的原因。因?yàn)槲覀€(gè)人習(xí)慣了C風(fēng)格的強(qiáng)制類型轉(zhuǎn)換。
  在C語言中,強(qiáng)制類型轉(zhuǎn)換就是用借助一對括號同時(shí)把類型名和表達(dá)式列出來,比如“(int)t”和“int(t)”就是把t轉(zhuǎn)為int型。
  引用:因?yàn)橐采w通常的標(biāo)準(zhǔn)轉(zhuǎn)換,所以需顯式使用強(qiáng)制類型轉(zhuǎn)換?!@式使用強(qiáng)制類型轉(zhuǎn)換的另一個(gè)原因是:可能存在多種轉(zhuǎn)換時(shí),需要選擇一種特定的類型轉(zhuǎn)換。
  筆記:從外文圖書翻譯過來的中國圖書有個(gè)通病,就是語言不倫不類。本書算是翻譯得非常好的了,依然無法擺脫這種影響。上文的意思無非是說:我不希望使用默認(rèn)的轉(zhuǎn)換規(guī)則的時(shí)候,就可以顯式地規(guī)定按我的要求轉(zhuǎn)換。如果要舉個(gè)例子,可以拿上文《類型轉(zhuǎn)換之隱式轉(zhuǎn)換》中一個(gè)現(xiàn)成的例子:
int a = -3;
unsigned b = 3;
if (a == b)//隱式轉(zhuǎn)換將轉(zhuǎn)為unsigned int
if (a == (int)b)//顯式指定轉(zhuǎn)換為int
  這種用法更多地用于指針類型的轉(zhuǎn)換。因?yàn)橹羔橆愋途褪侵羔標(biāo)赶驅(qū)ο蟮念愋?#xff0c;而指針本身是沒有類型區(qū)別的。所以,指向任何類型的指針可以互相轉(zhuǎn)換。最典型的就是void*和其它類型之間的互換了,比如:“int* p = (int*)malloc(sizeof(int) * MaxSize);”
  還有一種用法就是在編譯器不允許進(jìn)行隱式轉(zhuǎn)換的時(shí)候,比如將const對象轉(zhuǎn)為非const對象。如:
const int t = 3;
int* p = (int*)&t;//本來要寫作const int* p = &t;
  這種用法還是少用為好,理由很簡單,編譯器之所以不允許進(jìn)行轉(zhuǎn)換,就是為了保護(hù)數(shù)據(jù),你非要破壞這種安全性自然不好。即使能確信這樣做不產(chǎn)生惡果,這樣做至少是沒有良好風(fēng)格的。
  C++中為顯式類型轉(zhuǎn)換提供了四種不同的操作符:static_case、dynamic_cast、const_cast、reinterpret_cast。個(gè)人認(rèn)為與C風(fēng)格的相比似乎都沒有什么進(jìn)步。
  引用:強(qiáng)制類型轉(zhuǎn)換關(guān)閉或掛起了正常的類型檢查。強(qiáng)烈建議程序員避免使用強(qiáng)制類型轉(zhuǎn)換,不依賴強(qiáng)制類型轉(zhuǎn)換也能寫好很好的C++程序。
?
?
標(biāo)題::類對象的隱式轉(zhuǎn)換
與算術(shù)類型相比,類的轉(zhuǎn)換更復(fù)雜。因?yàn)樗阈g(shù)轉(zhuǎn)換只涉及到精度的問題,而類對象的轉(zhuǎn)換卻涉及到能否轉(zhuǎn)換以及怎樣轉(zhuǎn)換的問題。
  隱式轉(zhuǎn)換就是隱式轉(zhuǎn)換,它會(huì)出現(xiàn)在你沒有注意的地方。參看以下代碼:
class CMyInt
{
public:
  CMyInt();
  CMyInt(int i);
  ~CMyInt();
private:
  int m_i;
};
CMyInt::CMyInt()
{
  m_i = 0;
  cout << "無參數(shù)構(gòu)造(默認(rèn)0)" << endl;
}
CMyInt::CMyInt(int i)
{
  m_i = i;
  cout << "從整數(shù)構(gòu)造,值為" << i << endl;
}
CMyInt::~CMyInt()
{
  cout << "析構(gòu)" << m_i << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
  CMyInt a;
  a = 3;
  return 0;
}
  執(zhí)行以上代碼會(huì)發(fā)現(xiàn),程序中有兩次構(gòu)造與兩次析構(gòu),原因是“a = 3;”這個(gè)賦值表達(dá)式要將右邊的類型轉(zhuǎn)換為左邊的類型。而這個(gè)轉(zhuǎn)換是通過調(diào)用構(gòu)造函數(shù)來進(jìn)行的。
  不過,以上代碼只是測試用的,讀者們千萬不要在實(shí)際工作中寫這樣的代碼。因?yàn)檫@樣做是很不科學(xué)的?!癮 = 3;”這樣的表達(dá)式,只要CMyInt類提供了右值類型為int的賦值操作符重載,就可以避免使用構(gòu)造函數(shù)來進(jìn)行轉(zhuǎn)換。操作符重載代碼如下:
  在類定義的public段添加一行:“CMyInt& operator = (const int i);”然后在類定義外部添加以下代碼:
CMyInt& CMyInt::operator = (const int i)
{
  m_i = i;
  cout << "operator =" << i << endl;
  return *this;
}
  加了以上代碼,同樣是“a = 3;”就不使用類型轉(zhuǎn)換了,改為使用賦值操作。我寫下以上這段程序的目的只是驗(yàn)證VC++中會(huì)有類對象的轉(zhuǎn)換,它們與算術(shù)類型的轉(zhuǎn)換差不多:生成一個(gè)合適的臨時(shí)對象,參與運(yùn)算以后再把臨時(shí)對象釋放掉。
標(biāo)題::類型轉(zhuǎn)換之隱式轉(zhuǎn)換
對于我們來說,3+1.5=4.5。但是對于計(jì)算機(jī)來說,這兩個(gè)數(shù)的相加可不這么簡單。因?yàn)?與3.0是不同的數(shù)據(jù)類型,3.0與1.5是可以相加的,3卻不能與1.5相加。于是,C++在對上面的表達(dá)式進(jìn)行處理時(shí),有必要對其中一個(gè)(或兩者)進(jìn)行轉(zhuǎn)換。
  因?yàn)檫@個(gè)轉(zhuǎn)換是“隱式”的,也就是說這個(gè)轉(zhuǎn)換不讓程序員知道,那么,系統(tǒng)就不能必須保證不產(chǎn)生損失,這個(gè)損失指的是精度。為了不損失精度,數(shù)據(jù)總是向精度高的類型轉(zhuǎn)換。惟一的例外是當(dāng)某個(gè)變量用作條件時(shí),它被轉(zhuǎn)換為bool型。
  對算術(shù)類型的轉(zhuǎn)換是這樣的:所有比int小的都轉(zhuǎn)為int或unsigned int,即使沒有必要也這么轉(zhuǎn)。原因很簡單,因?yàn)閕nt的長度正好等于字長。對CPU來說,一次處理一個(gè)字是最快的。如果int或unsigned int無法達(dá)到要求,則往long、double轉(zhuǎn)化。
  如果每一個(gè)轉(zhuǎn)換都能不造成損失,那自然是好事。可是世間的事總有不隨人愿的時(shí)候。對于同一種算術(shù)類型,其signed和unsigned所能表達(dá)的范圍是一樣大,但卻是互不重疊的兩個(gè)范圍。就像“婦聯(lián)”和“工會(huì)”一樣,往哪邊轉(zhuǎn)換都可能會(huì)產(chǎn)生損失。這是無法解決的問題,所以,在VC中,試圖比較int和unsigned int變量時(shí)會(huì)顯示警告。
  奇怪的是,據(jù)我測試,在VC++.net中,只有進(jìn)行“<”和“>”比較的時(shí)候才會(huì)顯示警告,而進(jìn)行“==”和“!=”比較的時(shí)候卻不顯示警告。實(shí)際上這兩個(gè)比較也會(huì)有同樣的問題產(chǎn)生,比如以下代碼:
int a = -3;
unsigned b = 4294967293;
if (a == b) cout << "yes" << endl;
  測試運(yùn)行以上代碼會(huì)發(fā)現(xiàn)表達(dá)式a==b的值為true。這是從int轉(zhuǎn)為unsigned int過程中的副作用,這個(gè)副作用我們應(yīng)該知道,但是VC++.net不進(jìn)行任何警告似乎也有些與理不通?!y道我關(guān)閉了某些警告?
  其它隱式轉(zhuǎn)換還包括數(shù)組名轉(zhuǎn)換為指針、算術(shù)值用作條件時(shí)轉(zhuǎn)換為bool,枚舉被轉(zhuǎn)換為整數(shù),非const對象轉(zhuǎn)換為const對象等。其中枚舉轉(zhuǎn)換為整數(shù)沒什么要提的,枚舉值本來就是整數(shù)的別名,非const對象轉(zhuǎn)為const對象只是臨時(shí)聲明它的保護(hù)級別,通常用于作為參數(shù)傳遞時(shí)。
?
?
標(biāo)題::內(nèi)存管理之new和delete
林銳博士曾將內(nèi)存管理比喻為“雷區(qū)”(《高質(zhì)量C++/C編程指南》第44頁),內(nèi)存管理這塊難不難?恐怕不好說。“會(huì)者不難難者不會(huì)”嘛。但是說內(nèi)存管理這塊難以成為“會(huì)者”,應(yīng)該是沒有錯(cuò)的。
  程序時(shí)時(shí)刻刻與內(nèi)存打交道,只不過以往我們不用考慮,甚至不用知道。所以,所謂“內(nèi)存管理”,是特指堆內(nèi)存。
  如果把堆內(nèi)存和棧內(nèi)存的使用放在一起考慮,可以降低對內(nèi)存管理恐懼。
  一、內(nèi)存的分配:
  int i(100);//棧上分配內(nèi)存
  int *pi = new int(100);//堆上分配內(nèi)存
  以上兩種分配,都使用了100作為初始值進(jìn)行初始化,如果是進(jìn)行類對象的分配,它們還可以指定使用哪個(gè)構(gòu)造函數(shù),比如:
  CString s(s1);//棧上分配內(nèi)存
  CString *ps = new CString(s1)//堆上分配內(nèi)存
  這里的s可以是char*指針,也可以是另一個(gè)CString對象,它的類型將決定上面這兩行語句調(diào)用哪一個(gè)構(gòu)造函數(shù)。
  在這里,有一點(diǎn)要特別說明,如果要使用默認(rèn)構(gòu)造函數(shù),則new語句后面可以用空括號對,而棧內(nèi)分配的語句切不可用空括號對。如果寫成“CString s();”,則并不是定義一個(gè)CString對象s,而是定義一個(gè)返回值為CString的函數(shù)s。
  上面兩種分配,也都可以分配對象數(shù)組,不同的是,用new操作符在堆內(nèi)存分配數(shù)組時(shí),只能調(diào)用默認(rèn)構(gòu)造函數(shù)。而在棧上分配卻可以指定對象成員的初始值。如:
  int a[3] = {1,2,3};//棧上分配內(nèi)存,int可以換成其它類型名,后面的初始值可作相應(yīng)調(diào)整。
  int *p = new int[3];//不能指定這三個(gè)對象的初始值
  二、內(nèi)存的訪問:
  棧內(nèi)存可以通過對象訪問,也可以通過指針訪問,堆內(nèi)存通過指針訪問。方法完全相同。
  三、內(nèi)存的釋放:
  棧內(nèi)存在對象作用域結(jié)束后自動(dòng)釋放,堆內(nèi)存要用delete。
  delete pi;//釋放內(nèi)存
  delete []p;//釋放對象數(shù)組
  對于釋放對象數(shù)組,那個(gè)空的[]對不可以丟,否則將只釋放數(shù)組的第一個(gè)元素。導(dǎo)致內(nèi)存泄露。
  有了以上對比,堆內(nèi)存似乎沒有了任何難度。那么內(nèi)存管理的玄機(jī)究竟在哪兒呢?在進(jìn)行內(nèi)存分配與釋放的時(shí)候,有幾個(gè)注意點(diǎn)要記住:
  1、new操作有可能失敗,當(dāng)系統(tǒng)無法分配需要的內(nèi)存塊時(shí),將返回NULL值,所以在new操作之后,要立即判斷pi的值是否為NULL。
  int *pi = new int(100);
  if (pi = NULL) {...}
  2、堆上分配的內(nèi)存必須delete,而且只可以delete一次。為了保證內(nèi)存只被delete一次,請務(wù)必記住delete以后立即將指針設(shè)為NULL:
  delete pi;
  pi = NULL;
  雖然“pi=NULL;”不是必須的,但這是個(gè)好習(xí)慣。將指針設(shè)為NULL既可以防止繼續(xù)讀寫該內(nèi)存,也可以防止再次釋放該內(nèi)存。
  老的C程序員可能忘不了malloc和free函數(shù),它們也可以進(jìn)行內(nèi)存的分配與釋放。但是C++時(shí)代它們已經(jīng)落伍了。它們只是按請求的字節(jié)數(shù)進(jìn)行分配,而不管你用這塊內(nèi)存來干什么。這樣做,就等于放棄了類對象的構(gòu)造與析構(gòu)。對于很多類來說,這樣做是很危險(xiǎn)的。
?
?
標(biāo)題::優(yōu)先級、結(jié)合性和求值順序
說到優(yōu)先級,我能熟練背出“先乘除,后加減”,之于C++列出的整整19個(gè)優(yōu)先級,每個(gè)優(yōu)先級又包含若干個(gè)操作符,我總是看了就頭皮發(fā)麻。以我的記性,連軍旗里哪個(gè)大哪個(gè)小都背不出來,這幾十個(gè)操作符——還是饒了我吧。
  記住林銳博士的話:“如果代碼行中的運(yùn)算符比較多,用括號確定表達(dá)式的操作順序,避免使用默認(rèn)的優(yōu)先級?!?#xff08;《高質(zhì)量C++/C編程指南》第26頁)這樣做最直接的作用是不用記憶了復(fù)雜的優(yōu)先級了,不用記憶并不是因?yàn)閼?#xff0c;而是為了更清晰。畢竟程序不只是編給計(jì)算機(jī)運(yùn)行的,當(dāng)我們處在一個(gè)多人協(xié)作的團(tuán)體中時(shí),程序的清晰度和精確性比性能要高得多。再說,多加幾對括號是不影響運(yùn)行效率的。
  結(jié)合性和求值順序是容易混淆的兩個(gè)概念。每一個(gè)操作符都規(guī)定了結(jié)合性,但是只有極少數(shù)操作符規(guī)定求值順序。結(jié)合性是說如果有多個(gè)同級別的操作符,這些操作數(shù)該如何分組。比如“1+2+3”究竟分成“(1+2)+3”還是“1+(2+3)”,雖然這兩種分組最終沒有區(qū)別,但不等于所有操作符都不產(chǎn)生區(qū)別。即使不產(chǎn)生區(qū)別,計(jì)算機(jī)畢竟是計(jì)算機(jī),它只能按死的規(guī)范做事,于其給它靈活機(jī)制,還不如規(guī)定了結(jié)合性讓它遵守。
  C++只有四個(gè)操作符規(guī)定了求值順序,它們是“&&”、“||”、“?:”和“,”,記住這四個(gè)操作符并不難。反過來記住其它操作符也不難,難的是在寫程序中是否有這個(gè)意識。那么多網(wǎng)友討論“j = i++ + i++ + i++;”的結(jié)果,正說明了還有好多人不了解“未定義”的威力。如果不小心使用了依賴于未定義求值程序的語句,將是一個(gè)不容易發(fā)現(xiàn)并改正的問題。比如“if (a[index++] < a[index]);”
?
?
標(biāo)題::sizeof和逗號操作符
把sizeof說成操作符可能有些不合習(xí)慣,因?yàn)閟izeof的用法與函數(shù)沒區(qū)別。但是sizeof與函數(shù)有著本質(zhì)的區(qū)別:它是編譯時(shí)常量。也就是說,在程序編譯時(shí),就會(huì)求出它的值,并且成為程序中的常量。
  sizeof本身比較簡單,惟一要提的就是它對數(shù)組名和指針進(jìn)行操作的結(jié)果。
int a[10];
sizeof(a);
  該操作返回的是數(shù)組所有元素在內(nèi)存中的總長度。但是如果對指針進(jìn)行操作,返回的則是指針本身的長度,與指針?biāo)割愋蜔o關(guān)。
  正因?yàn)閿?shù)組名與指針有著千絲萬縷的關(guān)系,所以有時(shí)候這個(gè)特性會(huì)讓人摸不著頭腦:
int function(int a[10])
{
? sizeof(a);
? ...
}
  以上sizeof返回的不是數(shù)組所有成員的大小,而是指針的大小,因?yàn)閿?shù)組在參數(shù)傳遞中弱化為指針。
  逗號操作符除了在for語句中應(yīng)用以外,我沒發(fā)現(xiàn)在哪兒還有用處。因?yàn)樵谝话闱闆r下,逗號改成分號肯定是可以的,在for語句中因?yàn)榉痔柕淖饔昧碛卸x,所以不能隨便改。這才有了逗號的用武之地。
?
?
標(biāo)題::條件操作符
我覺得條件操作符的存在就是為了簡化if-else語句。第一,它與if-else語句的功能完全一致;第二,它雖然是一行語句,但是它規(guī)定了求解順序,這個(gè)順序保證了有些表達(dá)式不被求值。
  條件操作符是有一定的危險(xiǎn)性的,危險(xiǎn)的原因在于它的優(yōu)先級特別底,還容易漏掉括號。它的優(yōu)先級僅僅高于賦值和逗號運(yùn)算符,也就是說,只有在與賦值或逗號共存時(shí),才可以免去括號,其它情況下都得加上括號。漏加括號的BUG是很難發(fā)現(xiàn)的。
  比如“cout << (i < j) ? i : j;”這句的實(shí)際作用是將表達(dá)式“(i<j)”的值輸出,然后測試一下cout的狀態(tài)(<<操作符的返回值是cout),整個(gè)表達(dá)式的值不管是i還是j,都被丟棄。
?
?
標(biāo)題::箭頭操作符(->)
箭頭操作符是C++發(fā)明的全新操作符,但卻不是C++才用到的功能。早期的C語言雖然沒有類,卻有結(jié)構(gòu)體,也允許有指向結(jié)構(gòu)體對象的指針。不同的只是沒有發(fā)明“->”這個(gè)符號來進(jìn)行簡化操作。說到底,“->”的出現(xiàn)只是代替原來就可以實(shí)現(xiàn)的功能。
  引用:C++語言為包含點(diǎn)操作符和解引用操作符的表達(dá)式提供了一個(gè)同義詞:箭頭操作符(->)。
  筆記:這一同義詞的出現(xiàn),不僅僅使程序簡化而且更易于理解,更重要的是,它降低了出錯(cuò)的可能性。出什么錯(cuò)呢?這就跟操作符的優(yōu)先級有關(guān)了:
p->a();
(*p).a();
  以上兩行等價(jià),但是第二行卻很容易寫成“*p.a();”,由于點(diǎn)操作符的優(yōu)先級高,就成了“*(p.a());”,這里至少包含了兩個(gè)錯(cuò)誤:一是p不是對象,點(diǎn)操作無效;二是試圖對類成員解引用(只有當(dāng)該成員返回指針才有效)。
  也許有人要說了,第一個(gè)錯(cuò)誤已經(jīng)導(dǎo)致了編譯不通過,還要說第二個(gè)錯(cuò)誤干什么?這樣理解就錯(cuò)了。VC++為程序員提供了一個(gè)十分強(qiáng)大的庫,其中有些類的對象,既可以進(jìn)行點(diǎn)操作也可以進(jìn)行解引用操作的,如果上例中的p是那種類的對象,而且p.a()剛好又返回指針,那么上面這句將可以通過編譯,最終換來難以查找的BUG。
  記住,盡量多用箭頭操作符。
?
?
標(biāo)題::++的陷阱
自增和自減符作符是如此常用,以至于沒有必要提了。但是任何一本書都會(huì)下重手來提它,原因是它雖然簡單,卻含有玄機(jī)。
  講到前自增和后自增時(shí),幾乎所有的書都是這樣講的:用“j = i++”和“j = ++i”對比,告訴讀者雖然i都增了1,但是j卻不一樣。
  這也沒辦法,因?yàn)榻^大多數(shù)書在講到++時(shí)還沒有提到“表達(dá)式的值”這個(gè)概念,有些書本可能從頭到尾都不提。對于“j = i++;”來說,它是一個(gè)表達(dá)式?jīng)]錯(cuò),但是等號右側(cè)也是一個(gè)表達(dá)式,對于表達(dá)式“i++”來說,它是有值的,該表達(dá)式的值賦予了j,而整個(gè)表達(dá)式也有一個(gè)值,只是這個(gè)值被丟棄了。類推:“i = j = k = 1;”語句中單獨(dú)的“1”就是一個(gè)表達(dá)式,叫常量表達(dá)式,它的值就是1,它給了k,“k=1”這個(gè)表達(dá)式也有值,它的值就是k的值,它給了j,……最后給i賦值的表達(dá)式也有值,它的值就是i的值,這個(gè)值被丟棄。
  弄明白了“表達(dá)式的值”后,就可以科學(xué)地講解“++i”和“i++”了,因?yàn)檫@兩個(gè)表達(dá)式的值是這樣定義的:前置自增/減表達(dá)式的值是修改后的變量值,后置則為修改前的值。
  那么,在不關(guān)心表達(dá)式的值的時(shí)候——即只是給某變量自增或自減一下——究竟用哪個(gè)好呢?當(dāng)然是前置好,因?yàn)榍爸弥灰靡粋€(gè)指令進(jìn)行一下自增自減運(yùn)算,然后直接返回即可。而后置卻要先保存好這個(gè)初始值,再自增減,然后再返回以前保存的值。寫過操作符重載的程序員應(yīng)該更能體會(huì)這里面的區(qū)別。
  “++i”或“i++”是這樣簡潔,所以它們比“i = i + 1;”要美得多,所以書上說“簡潔就是美”。但是,在美的同時(shí),一個(gè)美麗的陷阱正在招手,程序員們必須理解并小心。
  “if (ia[index++] < ia[index])”這樣的表達(dá)式是危險(xiǎn)的。前文中已經(jīng)提到了,C++中只有極少的幾個(gè)操作符是規(guī)定了求值順序的,“<”號沒有規(guī)定,那么,這兩個(gè)數(shù)要比較大小,系統(tǒng)究竟先求前者還是后者?如果先求前者,那么求后者的時(shí)候index是值有沒有增一?
  經(jīng)常在論壇上看到有人討論“j = i++ + i++ + i++;”的結(jié)果,還有人把自己的實(shí)踐結(jié)果貼出來證實(shí)自己的理論。這正是初學(xué)者令人悲哀與同情的地方:對于應(yīng)該好好掌握的知識沒有足夠的熱情,卻把一腔熱血放在這些無須討論的話題上,C++初學(xué)者要走的路不僅長,而且充滿了荊棘。
?
?
標(biāo)題::回憶十幾年前的編程入門
本來不想為這段寫讀書筆記,不過突然想起十幾年前的一件趣事來,還是記下來吧。
  1993年的時(shí)候,學(xué)校開設(shè)了“勞技”課,講的是BASIC語言。對于當(dāng)時(shí)連電腦都沒看過一眼的我們來說,學(xué)校開設(shè)這樣的課,真是讓我們無比感動(dòng)。我至今仍然感謝我的母校,在片面追求升學(xué)率、大量縮減副課的全局下,我的母校居然開設(shè)了音樂、美術(shù)、勞技等一系列副之又副的課。這讓我至今難忘。而令一方面,我今天能夠在程序界打拼,完全是從那時(shí)候開始陪養(yǎng)的興趣。如果我的高中沒有開設(shè)這門課,我未必就不進(jìn)入程序界,但是入門至少要晚三年。
  這三年,我學(xué)的編程東西少之又少,對于整個(gè)BASIC來說,簡直連皮毛都不如,而且學(xué)校只提供了一次上機(jī)機(jī)會(huì),練的是開機(jī)與關(guān)機(jī)。我所謂的“調(diào)試程序”是在自己的小霸王學(xué)習(xí)機(jī)上進(jìn)行的。但是,在電腦沒有普及的年份,懂得一點(diǎn)點(diǎn)就是很先進(jìn)的了。進(jìn)入大學(xué)后,堂堂一個(gè)大學(xué)的班級,居然只有兩個(gè)人碰過電腦,大家的基礎(chǔ)可想而知。在同學(xué)們拼命學(xué)習(xí)DOS命令的時(shí)候,我已經(jīng)遙遙地走在了前面。之后學(xué)習(xí)True Basic自然一日千里,之后自學(xué)VB、自學(xué)C也就順理成章。如果我的高中沒有開設(shè)這門課,我未必就不進(jìn)入程序界,但是我在進(jìn)大學(xué)的頭一段時(shí)間肯定會(huì)與其他同學(xué)一起拼命記DOS命令。要知道,其他同學(xué)至所以學(xué)得比我慢,并不是比我笨,而是沒有習(xí)慣電腦的思維模式。
  該說“賦值操作符”了。高中開設(shè)的BASIC語言課,其課本是不到半厘米厚的小書。但是我愛不釋手地提前閱讀了。讀得一知半解就去做后面的習(xí)題,發(fā)現(xiàn)一句“P=P+1”,心想:這怎么可能嘛?P怎么可能等于P加一呢?移項(xiàng)一減,不就相當(dāng)于0=1了嗎?一定是書上印錯(cuò)了。于是,我將其中一個(gè)P改成了R,而且是用黑鋼筆描的。我描得是如此細(xì)致,以至于根本看不出那個(gè)R是P改的。等到老師講到這一節(jié)的時(shí)候,我雖然已經(jīng)懂了這里的“=”與數(shù)學(xué)上的“=”不一樣,但是由于把P看成了R,這題還是做錯(cuò)了。
  當(dāng)時(shí)的情況是這樣的:老師喊了幾個(gè)同學(xué)上去做題,沒有一個(gè)會(huì)。老師說“有沒有誰會(huì)做的?主動(dòng)上來?”好幾個(gè)同學(xué)立即喊我的名字,把我逼上去了。結(jié)果我這么一做就做錯(cuò)了。老師表揚(yáng)了我的勇氣,但是同學(xué)卻說我雖然平時(shí)捧著這本書不放,原來也是個(gè)“菜鳥”。
  賦值操作符就是在那個(gè)時(shí)候給我留下深刻印像的,那天我知道了,“=”號不表示左右相等。
  復(fù)合賦值操作符也比較簡單,理解了它的用法就好了。C++至所以有了賦值操作符以后還要復(fù)合賦值操作符,不僅僅是為了簡化代碼,還可以加快處理速度?!癷=i+j”和“i+=j”相比,前者的i求值了兩次。不過,這點(diǎn)性能差別對整個(gè)程序性能來說不大。還有一個(gè)區(qū)別就是優(yōu)先級方面的了。“i*=j+1”如果不寫成復(fù)合賦值,就要加上括號:i=i*(j+1)。
?
?
標(biāo)題::關(guān)系、邏輯和位操作符
關(guān)系操作符本身沒什么好提的,它們與我們平時(shí)身邊的邏輯一樣,所以不難理解。有兩點(diǎn)可以略提一下:
  一、因?yàn)锳SC字符中沒有“≥”這些符號,所以只好用“>=”代替。于是產(chǎn)生了BASIC和C++的兩種不同符號集:BASIC用“<>”表示不等于,C++則用“!=”。
  二、程序設(shè)計(jì)時(shí)不能用“if (i < j < k)”這樣的寫法。原因很簡單,因?yàn)檫@種寫法另有含義,或者說正因?yàn)椴荒苓@樣寫,才給這種寫法另外賦了一種含義。
  BASIC和C++的邏輯操作符也有完全不同的寫法,BASIC用比較直觀的關(guān)鍵字“And”、“Or”之類,C++則用“&&”和“||”。這也沒什么,記住就行了。
  邏輯操作符中的“&&”和“||”是C++標(biāo)準(zhǔn)中為數(shù)不多的指定了求值順序的操作符(除此以外還有條件操作符“?:”和逗號操作符“,”,關(guān)于求值順序,后面還將提及)。這樣的規(guī)定惟一的缺點(diǎn)是需要額外的記憶,優(yōu)點(diǎn)則是很明顯的:它可以讓“危險(xiǎn)”的操作變得不危險(xiǎn)。如“while (i<MaxSize && Array[i]>0)”,對于“Array[i]”來說,指針越界是很可怕的,但是“&&”操作符的求值順序保證了指針不越界。從另一方面說,要保證指針不越界,就必須記住該操作符的求值順序(不然就只能分成兩個(gè)語句寫嘍)。
  又要提到bool值的比較了,“if (i < j < k)”的實(shí)際就是進(jìn)行了bool值的比較。本書在講解的時(shí)候,雖然提到了“將k與整數(shù)0或1做比較”,但是我寧可提醒大家不去記住這個(gè)。記住bool值只有true和false兩個(gè)值,比記住1和0要好得多,因?yàn)殡m然false就是0,但是true卻不僅是1。
  C++中如果只有邏輯操作符也就算了,它偏偏還有“&”和“|”這樣的位操作符。而位操作正是BASIC不提供的功能。這就給初學(xué)C/C++的人帶來了難度。難點(diǎn)不在于理解,而在于記憶。位操作符的作用是進(jìn)行某一Bit位的設(shè)定,在一個(gè)字節(jié)掰成八份用的年代,它非常常用,—比如Turbo C中的屏幕設(shè)置,就是3位表示背景色、4位表示前景色、一位表示閃爍,用一個(gè)字節(jié)完全存放了屏幕字體的信息?,F(xiàn)在的海量存儲與高速處理中,大可不必這么節(jié)約了(從處理速上看,非但沒有節(jié)約,反而浪費(fèi)了),所以,不會(huì)位操作也沒什么大不了的。
  不過,不熟悉位操作的用戶卻都知道“<<”和“>>”的另一用處。這事不能怪程序員,幾乎所有的C++書本都會(huì)從“cin >> i;”和“cout << i;”入手。不用知道這兩個(gè)操作符原來是干什么的,甚至不用知道“重載”是怎么回事。C++來到這個(gè)世界,發(fā)展了C語言,使得“知其然不知道其所以然”的程序員也能好好工作。也許這是它的一個(gè)進(jìn)步吧。
?
?
標(biāo)題::可愛的算術(shù)操作符
算術(shù)操作符是最容易理解的符號了,因這它與平時(shí)做的數(shù)學(xué)是完全相同的規(guī)則。就連小學(xué)的知識“先乘除后加減”都完全適用。
  不過,就像因?yàn)榕c生活的邏輯完全一樣導(dǎo)致易于理解一般,與生活邏輯不一致的問題就比較難以理解了。比如“有9個(gè)蘋果,3個(gè)小朋友分,平均每個(gè)小朋友可以分到幾個(gè)蘋果?”,現(xiàn)實(shí)中既不可能是-9個(gè)蘋果,也不可能給-3個(gè)小朋友分。而是C/C++中的除法和求余卻不得不面對這種情況。它們非但難于理解,而且還有不確定因素。
  引用:如果兩個(gè)操作數(shù)都為正,除法和求模操作的結(jié)果也是正數(shù)(或零);如果兩個(gè)操作數(shù)都是負(fù)數(shù),除法操作的結(jié)果為正數(shù)(或零),而求模操作的結(jié)果則為負(fù)數(shù)(或零);如果只有一個(gè)操作數(shù)是負(fù)數(shù),這兩種操作的結(jié)果取決于機(jī)器;求模結(jié)果的符號也取決于機(jī)器,而除法操作的值則是負(fù)數(shù)(或零)。
  筆記:以上這一大堆似乎有些費(fèi)口舌。這么說吧,如果兩個(gè)數(shù)同號,則一切都那么簡單。即使是兩個(gè)負(fù)數(shù)相除,只要把它們當(dāng)成兩個(gè)正數(shù)就可以了——商肯定是正的,余數(shù)只要對應(yīng)調(diào)整一下符號即可;如果是一正一負(fù)兩個(gè)數(shù)相除,那么商肯定是負(fù)的,但是究竟是負(fù)多少可不一定,余數(shù)就更難說了,連是正是負(fù)都不能確定。
21 % 6 = 3;
21 % 7 = 0;
-21 % -8 = -5;
21 % -5 = ?;//與機(jī)器相關(guān),可能是1可能是-4
21 / 6 = 3;
21 / 3 = 3;
-21 / -28 = 2;
21 / -5 = ?;//與機(jī)器相關(guān),可能是-4或-5
  引用:當(dāng)只有一個(gè)操作數(shù)為負(fù)數(shù)時(shí),求模操作結(jié)果值的符號可依據(jù)分子(被除數(shù))或分母(除數(shù))的符號而定。如果求模的結(jié)果隨分子的符號,則除出來的值向零一側(cè)取整;如果求模與分母的符號匹配,則除出來的值向負(fù)無窮一側(cè)取整。
  10個(gè)蘋果分給-3個(gè)朋友,平均每個(gè)小朋友可以分到幾個(gè)?還剩下幾個(gè)?
?
?
標(biāo)題::操作符
第五章開始了,看得出來,從這章才真正開始講解C++的基本內(nèi)容。沒有這里的內(nèi)容,前四章都是狗屎。
  操作符就是我們平時(shí)理解的“運(yùn)算符”了,不過因?yàn)镃++是計(jì)算機(jī)語言,它與我們平時(shí)生活有著不一樣的邏輯,所以,在我們平時(shí)看來簡單的“3+4”,到了C++里,就得分成一個(gè)操作符和兩個(gè)操作數(shù)了。
  操作符的含義以及它能得到的結(jié)果,不僅僅取決于操作符本身,還同時(shí)取決于操作數(shù)。當(dāng)初學(xué)C語言的時(shí)候,發(fā)現(xiàn)做除法要用“10/3.0”而不用“10/3”著實(shí)驚訝了一回。特別是從BASIC走過來的人,BASIC里沒有這么強(qiáng)的類型,所以10/3就是浮點(diǎn)數(shù),要整除還得用“Int()”函數(shù)或改用“/”運(yùn)算符(不是每個(gè)VB程序員都知道這個(gè)運(yùn)算符的哦。)
  從C/C++中弄明白了“10/3.0”和“10/3”,反過來再去理解C與BASIC的區(qū)別,不難發(fā)現(xiàn)C/C++這樣做的確比BASIC高明得多。而進(jìn)一步了解了硬件的運(yùn)算機(jī)制后,則可以理解這樣做不僅僅是高明,而且是必須。
  引用:有些符號既可以表示一元操作也可以表示二元操作。例如*……,這種兩用法相互獨(dú)立、各不相關(guān),如果將其視為兩個(gè)不同的符號可能會(huì)更容易理解些?!枰鶕?jù)該符號所處的上下文來確定它代表一元操作還是二元操作。
  筆記:這是一個(gè)大家都明白,但是大家都不會(huì)去想的問題。細(xì)想起來,我們不去想,正是因?yàn)槲覀冊缫咽熘?。然而我們讀程序可以上下關(guān)聯(lián),計(jì)算機(jī)要做到這點(diǎn)就不容易——比如拼音輸入法的自動(dòng)選詞。由此看來,C++編譯器是十分優(yōu)秀的人工智能軟件。
?
?
標(biāo)題::多維數(shù)組
引用:嚴(yán)格地說,C++中沒有多維數(shù)組。
  筆記:不只是C++啦,C中就是這樣。不過,正因?yàn)镃++中沒有多維數(shù)組,而提供了“數(shù)組的數(shù)組”,所以C/C++在數(shù)組使用上更靈活。
  多維數(shù)組的定義和使用沒什么要多提的,用過就懂了。無非是多一對括號而已。不過,如果把它跟指針一起用,倒是要注意的:二維數(shù)組名對應(yīng)的是“指向指針的指針”,所以,如果要在函數(shù)間傳遞多維數(shù)組,指針類型一定要正確:
  int a[3][4];
  int *p1 = &a[0][0];//a[][]是一個(gè)int,對其取地址就是int*
  int *p2 = a[0];//a[0]雖然是a有一個(gè)元素,但它也是另一個(gè)數(shù)組的數(shù)組名
  int **p3 = a;//a是一個(gè)二維數(shù)組的數(shù)組名
  int **p4 = &a[0];//a[0]是一個(gè)數(shù)組名,它是a數(shù)組的一個(gè)成員
  另外,有一個(gè)比較難記、容易混淆的用法:
  int (*p5)[4] = a;
  說它容易混淆,是因?yàn)樗c“int *p5[4];”有著截然不同的意義。前者是指定義一個(gè)指向數(shù)組的指針,后者則是定義一個(gè)指針數(shù)組?!^昏ing...
  本人在實(shí)際使用中,經(jīng)常避開多維數(shù)組,而用其它途徑來使用一大堆數(shù)值。比如可以這樣用:
  int a, b;//兩維的元素個(gè)數(shù)
  int *p = new int[a*b];
  for (int i=0; i<a; ++i)
    for (int j=0; j<b; ++j)
      p[i*a+j].....;
  delete []p;
  用這種方法,就是三維、四維也不用考慮“指向指針的指針”這么復(fù)雜的東西。不是我不會(huì),而是不高興去想。
?
?
標(biāo)題::動(dòng)態(tài)數(shù)組
我暈,本書才講了個(gè)開頭,居然講到new和delete了。我“偷窺”了一下:下一章開始才講到操作符,而且下章將有專門的一節(jié)講new和delete。看來這里提到它們的目的只是為了說明string這樣的類為什么可以自動(dòng)適應(yīng)大小。
  new的返回值是一個(gè)指針,不過本書暫時(shí)沒有提到new也會(huì)返回NULL的。是的,暫時(shí)還不用提內(nèi)容不夠這么復(fù)雜的情況。
  引用:在自由存儲區(qū)中創(chuàng)建的數(shù)組對象數(shù)組是沒有名字的,程序員只能通過其地址間接地訪問堆中的對象。
  筆記:這里有兩個(gè)問題,一是“數(shù)組的名字”其實(shí)也是個(gè)指針,指針當(dāng)然也可以看成“數(shù)組的名字”,這本來就可以互換的,正如我前面說的一樣:“5[a]”完全等價(jià)于“*(5+a)”。至于a是靜態(tài)的數(shù)組名還是動(dòng)態(tài)的指針,沒有區(qū)別。第二個(gè)問題是這里提到了“堆”,在沒有講解內(nèi)存之前,這樣說畢竟理解上有難度。還是那句話,這本書是給有一定基礎(chǔ)的人看的。
  令我耳目一新的是:new還能創(chuàng)建const數(shù)組?!皇俏也欢?#xff0c;而是實(shí)在沒想到。再說了,創(chuàng)建一大堆const的內(nèi)容,而且只能初始化為同一個(gè)值。那這有什么用?正如本書提到的一樣:“這樣的數(shù)組實(shí)際上用處不大”。依我看,不是用處不大,而是根本沒用。
  動(dòng)態(tài)空間的釋放應(yīng)該用“delete []p;”而不是“delete p;”,這是一個(gè)只要記住就可以的問題,我之所以提上一句,是因?yàn)橛腥藳]有注意過這個(gè)細(xì)節(jié),包括很多自以為很了不起的程序員。
  引用:如果遺漏了方括號對,這是一個(gè)編譯器無法發(fā)現(xiàn)的錯(cuò)誤,將導(dǎo)致程序在運(yùn)行時(shí)出錯(cuò)。
?
?
標(biāo)題::C風(fēng)格字符串
給這篇文章定下這個(gè)標(biāo)題:,是因?yàn)闀芯褪沁@樣說的。本書是講解C++的,所以它推薦讀者盡量使用C++的內(nèi)容,而實(shí)際上像我這樣從C過來的人,還是習(xí)慣于使用C風(fēng)格的字符串?!矣窒肫鹆四蔷湓?#xff1a;“原來我只是一個(gè)‘古代’的C++程序員?!?見《數(shù)組》一文)
  C語言是用字符數(shù)組來做字符串的(當(dāng)然這個(gè)字符數(shù)組必需要有一個(gè)NULL結(jié)尾),因?yàn)樽址侨绱顺S?#xff0c;C語言還專門開發(fā)了一套庫函數(shù)來處理這個(gè)特殊的數(shù)組。于是,我們進(jìn)行字符串操作時(shí),可以忘記指針、忘記循環(huán)、還可以忘記char這個(gè)內(nèi)置類型。
  正是因?yàn)槿绱?#xff0c;林銳博士的《高質(zhì)量C++/C編程指南》中還特別強(qiáng)調(diào),不可以用指針的賦值和比較來進(jìn)行字符串的賦值和比較。這個(gè)警告對于從VB轉(zhuǎn)過來的人尤其重要。
  使用C風(fēng)格的字符串有兩點(diǎn)是必須保證的:一是要給這個(gè)數(shù)組開劈足夠長度的空間;二是一定不要忘了NULL;其中第二點(diǎn)一般程序員不會(huì)犯錯(cuò),因?yàn)楫吘箾]幾個(gè)人用“chat s[3] = {'a', 'b', '/0'}”這種方式來定義字符串。第一點(diǎn)就成了重中之重。我們在strcpy之前,有沒有考慮過目標(biāo)字符串可能的空間不足?
  “strn”風(fēng)格的函數(shù)既救了大家也可能害了大家,說它救了大家,因?yàn)榇蠹以趕trncpy和strncat時(shí)可以控制字符個(gè)數(shù),即使源字符串太長,也可以避免內(nèi)存溢出。但是它存在的危險(xiǎn)性是它不會(huì)為目標(biāo)字符串添加NULL。
  所以,書寫到這里再次做了一個(gè)提醒:“盡可能使用標(biāo)準(zhǔn)庫類型string”——我都忘了這是第幾次提醒了,本書一而再再而三地提醒讀者不要做“古代”的C++程序員。
?
?
標(biāo)題::指針(三)指針與數(shù)組
指針和數(shù)組之間是什么關(guān)系呢?書中曰“密切相關(guān)”。其實(shí),那簡真就是同一回事嘛。用到指針的時(shí)候,你未必會(huì)用到數(shù)組;但是只要你用到數(shù)組,你就必要然用到指針(即使你不知道)。
  正是因?yàn)橹羔樋梢杂眉踊驕p運(yùn)算來移動(dòng)它所指的位置,而且每加一或減一正好移動(dòng)到相鄰一個(gè)同類型的變量(不管這個(gè)變量占內(nèi)存是多少),那么我有意將一堆同類型的變量放在一起,拿一個(gè)指針指向它們中的第一個(gè),再記住它們的個(gè)數(shù),這就成了數(shù)組。
  數(shù)組用一組方括號來解引用其中的某個(gè)成員,這也只是指針運(yùn)算的簡化。比如:
  int a[10];
  a[5] = 5;
  以上這種代碼誰都用過,誰都能理解。那么下面這行代碼呢?
  5[a] = 5;
  這種用法恐怕很少有人知道,即使現(xiàn)在知道了,恐怕也很難理解。實(shí)際上知道了數(shù)組運(yùn)算的實(shí)質(zhì),這行代碼的迷霧就會(huì)立即消失:C/C++語言處理括號的方法很簡單,將方括號前面的值和方括號內(nèi)的值相加,得到一個(gè)新的指針,再取指針?biāo)傅膶ο笾??!癮[5]”就完全等價(jià)于“*(a+5)”,“5[a]”就完全等價(jià)于“*(5+a)”。
  那么“*(a+5)”是什么運(yùn)算呢?指針運(yùn)算。因?yàn)樵诰幾g器處理“int a[10];”的時(shí)候,就等于定義了一個(gè)“int * const a;”同時(shí)將它初始化為指向棧內(nèi)存的某處。
  實(shí)際上,正是因?yàn)椤?(a+5)”這種用法實(shí)在太常用了,C才規(guī)定了它的替代用法,后來這個(gè)替代用法被廣為接受,而它的實(shí)際卻被人遺忘。
  以上內(nèi)容本書未有提及,這是我看書看到這里的一點(diǎn)心得,作為讀書筆記寫下來。不是為了炫耀。本書雖然是給有一定基礎(chǔ)的人讀的,但是畢竟它只是按步就章地寫下C++的語法規(guī)則,沒有必要提及這些技巧性高而又實(shí)用性少的內(nèi)容。我之所以要寫下來,目的是為了便于理解指針運(yùn)算。
?
?
標(biāo)題::指針(二)
指針的初始化與賦值:指針是一個(gè)變量,它可以被賦值,也可以被求值。指針可以接受的值只有以下幾種:
  1、編譯時(shí)可求值的0值常量。(必須是0,其實(shí)就是NULL啦)
  2、類型匹配的對象的地址。(也就是用&運(yùn)算符取一個(gè)變量的地址)
  3、另一對象末的下一地址。(這種用法主要用在循環(huán)里,其實(shí)當(dāng)指針取這個(gè)值時(shí),對其所指的內(nèi)存進(jìn)行存取往往會(huì)導(dǎo)致災(zāi)難)
  4、同類型的另一個(gè)有效指針(如“p=q;”)。
  其中第1點(diǎn),將0值賦給指針,主要是為了有一個(gè)狀態(tài)表示這個(gè)指針是“空的”。C/C++通常約定0為NULL,雖然的確存在地址為0的內(nèi)存,但是別指望用指針來訪問這個(gè)內(nèi)存。
  初學(xué)者怎樣才能消除對指針的恐懼?我覺得首要的一點(diǎn)是清醒地認(rèn)識并且時(shí)刻提醒自己“指針也是一個(gè)變量”。比如以下兩行程序:
  int i;
  int *p = &i;
  看到這兒的人幾乎無一例外把p和i聯(lián)系起來(這當(dāng)然不是壞事),但是,我覺得更重要的是將p和i分離,心里記住,p是一個(gè)變量,該變量是有它的值的,這個(gè)值與i的唯一關(guān)系是:目前該值正好等于變量i在內(nèi)存中的位置。兩種情況下p與i將毫無關(guān)系:
  1、p值被改變,如“p = &j;”或“p++;”
  2、i變量被釋放,如離開了i的作用域。
?
?
標(biāo)題::指針
指針是C/C++的精華,也是最難的部分?!袑W(xué)習(xí)C/C++的人都明白這點(diǎn),當(dāng)年我初學(xué)的時(shí)候也是這樣。但是,現(xiàn)在再回想指針,我卻很難回憶它究竟難在哪兒。應(yīng)該說這就叫“難者不會(huì),會(huì)者不難”吧。“飽漢不知餓漢饑”是有一定的道理的,即使飽漢曾經(jīng)餓過。
  本書中規(guī)中矩地講解了指針的概念、定義與初始化、操作等。正如上面提到的“飽漢不知餓漢饑”,我似乎很健忘,以至于不記得指針的難點(diǎn)在哪兒了。
  指針的靈活性可以把大量的工作化繁為易,前提是必須首很把足夠繁的指針弄懂。聽起來有點(diǎn)像繞口令,事實(shí)就是這樣,你現(xiàn)在把難懂的東西弄懂了,日后可以把難事化簡,大事化小。
  從VB過來的人一定會(huì)熟悉“值傳遞”和“地址傳遞”這兩個(gè)概念,實(shí)際上,“地址傳遞”這種說法正是為了彌補(bǔ)VB沒有指針卻有類似的需要才發(fā)明的。我認(rèn)為C/C++程序員要想深入理解指針,首先要拋棄這個(gè)概念。在C/C++程序中,即使在函數(shù)調(diào)用中傳遞指針,也不能說“地址傳遞”,還應(yīng)該說是值傳遞,只不過這次傳遞的值有點(diǎn)特殊,特殊在于借用這個(gè)值,可以找到其它值。就好像我給你一把鑰匙一樣,你通過鑰匙可以間接獲得更多,但是我給你的只不過是鑰匙。
  我前陣子曾寫過一篇關(guān)于指針的文章,之所以寫那篇文章,是因?yàn)榭吹揭淮蠖殉鯇W(xué)者在論壇上提問。通過對他們提的問題的分析,我總結(jié)了幾點(diǎn)。下面,首先就先引用我自己寫的《關(guān)于指針》中的片段吧(完整的文章請到我的個(gè)人主頁查找):
  一、指針就是變量:
  雖然申明指針的時(shí)候也提類型,如:
  char *p1;
  int *p2;
  float *p3;
  double *p4;
  .....
  但是,這只表示該指針指向某類型的數(shù)據(jù),而不表示該指針的類型。說白了,指針都是一個(gè)類型:四字節(jié)無符號整數(shù)(將來的64位系統(tǒng)中可能有變化)。
  二、指針的加減運(yùn)算很特殊:
  p++、p--之類的運(yùn)算并不是讓p這個(gè)“四字節(jié)無符號整數(shù)”加一或減一,而是讓它指向下一個(gè)或上一個(gè)存儲單元,它實(shí)際加減的值就是它所指類型的值的size。
  比如:
  char *型指針,每次加減的改變量都是1;
  float *型的指針,每次加減的改變量都是4;
  void *型指針無法加減。
  還要注意的是:指針不能相加,指針相減的差為int型。
  正是因?yàn)橹羔樣兄煌谄渌兞康倪\(yùn)算方式,所以,在任何時(shí)候用到指針都必須明確“指針的類型”(即指針?biāo)傅淖兞康念愋?#xff09;。這就不難理解為什么函數(shù)聲明時(shí)必須用“int abc(char *p)”而調(diào)用的時(shí)候卻成了“a = abc(p);”這樣的形式了。
  三、用指針做參數(shù)傳遞的是指針值,不是指針本身:
  要理解參數(shù)傳遞,首先必須把“形參”與“實(shí)參”弄明白。
  函數(shù)A在調(diào)用函數(shù)B時(shí),如果要傳遞一個(gè)參數(shù)C,實(shí)際是在函數(shù)B中重新建立一個(gè)變量C,并將函數(shù)A中的C值傳入其中,于是函數(shù)B就可以使用這個(gè)值了,在函數(shù)B中,無論有沒有修改這個(gè)C值,對于函數(shù)A中的C都沒有影響。函數(shù)B結(jié)束時(shí),會(huì)將所有內(nèi)存收回,局部變量C被銷毀,函數(shù)B對變量C所做的一切修改都將被拋棄。
  以上示例中,函數(shù)A中的變量C稱為“實(shí)參”,函數(shù)B中的變量C被稱為“形參”,調(diào)用函數(shù)時(shí),會(huì)在B函數(shù)體內(nèi)建立一個(gè)形參,該形參的值與實(shí)參的值是相同的,但是形參的改變不影響實(shí)參,函數(shù)結(jié)束時(shí),形參被銷毀,實(shí)參依然沒有發(fā)生變化。
  指針也是一個(gè)變量,所以它也符合以上的規(guī)定,但是,指針存放的不僅僅是一個(gè)值,而是一個(gè)內(nèi)存地址。B函數(shù)對這個(gè)地址進(jìn)行了改動(dòng),改動(dòng)的并不是形參,而是形參所指的內(nèi)存。由于形參的值與實(shí)參的值完全相同,所以,實(shí)參所指的內(nèi)存也被修改。函數(shù)結(jié)束時(shí),雖然這個(gè)形參會(huì)被銷毀,指針的變化無法影響實(shí)參,但此前對它所指的內(nèi)存的修改會(huì)持續(xù)有效。所以,把指針作為參數(shù)可以在被調(diào)函數(shù)(B)中改變主調(diào)函數(shù)(A)中的變量,好像形參影響了實(shí)參一樣。
  注意:是“好像”。在這過程中,函數(shù)B影響的不是參數(shù),而是內(nèi)存。
  下面再來看剛才的例子:“int abc(char *p)”和“a = abc(p);”。為什么申請中要用*號,因?yàn)楹瘮?shù)必須知道這是指針;為什么調(diào)用時(shí)不加*號,因?yàn)閭鬟f的是“指針值”,而不是“指針?biāo)竷?nèi)存的值”。
  四、指向指針的指針:
  正因?yàn)橹羔樢彩且粋€(gè)變量,它一樣要尊守形參與實(shí)參的規(guī)定。所以,雖然指針做參數(shù)可以將函數(shù)內(nèi)對變量的修改帶到函數(shù)外,但是,函數(shù)體內(nèi)對指針本身作任何修都將被丟棄。如果要讓指針本身被修改而且要影響函數(shù)外,那么,被調(diào)函數(shù)就應(yīng)該知道“該指針?biāo)诘膬?nèi)存地址”。這時(shí),指針不再是指針,而是“普通變量”。作為參數(shù)傳遞的不是這個(gè)“普通變量”,而是指向這個(gè)“普通變量”的指針。即“指向指針的指針”。
  如果p是一個(gè)指向指針的指針,那么*p就是一個(gè)指針,我們不妨就把它看成q。要訪問q指針?biāo)傅膬?nèi)存,只要*q就是了。用初中數(shù)學(xué)的“等量代換”一換就知道,*q就是**p。
  五、指針數(shù)組。
  之所以要把“指針數(shù)組”單獨(dú)提出來,是因?yàn)閿?shù)組本身就與指針有著千絲萬縷的關(guān)系。即使你不想用指針,只要你使用了數(shù)組,實(shí)際就在與指針打交道了。
  只要理解了指針本身就是變量,就不難理解“指針數(shù)組”,我們可以暫且把它當(dāng)成普通數(shù)組來處理,a[0]、a[1]、a[2]……就是數(shù)組的元素,只是,a[0]是一個(gè)指針,a[1]、a[2]也是一個(gè)指針。那a呢?當(dāng)然也是指針,但這是兩碼事。你可以完全無視a的存在,只去管a[0]等元素。*a[0]與*p沒有什么本質(zhì)的區(qū)別?! ?br />  還有一個(gè)東西不得不提一下,它比較重要:
  指針的定義有兩個(gè)可取的方式,它們各有優(yōu)缺點(diǎn):“int *p;”和“int* p;”是完全等價(jià)的,后者的好處是讓人體會(huì)到p是一個(gè)“指向int的”指針,前者會(huì)讓人誤解為*p是一個(gè)int型變量(這里沒有定義int型變量);但是前者的好處是不會(huì)產(chǎn)生混淆,如“int *p, *q;”讓人一眼就看出定義了兩個(gè)指針,而“int* p,q;”會(huì)讓人誤解成定義了兩個(gè)指針(實(shí)際上q不是指針)。
?
?
標(biāo)題::數(shù)組
進(jìn)入本書第四章,開始講“數(shù)組”了。數(shù)組難不難?這不好說。但是數(shù)組非常重要這是肯定的,有許多基本的算法就是與數(shù)組一起出現(xiàn)的——比如冒泡排序法。而離開了那些算法,數(shù)組本身也失去了價(jià)值。
  注意:閱讀本章時(shí)要對“維數(shù)”概念加以小心,按平時(shí)的理解,“維數(shù)”是多維數(shù)組中的概念,但是本書中的“維數(shù)”指的是元素個(gè)數(shù)。為了避免干擾,我在閱讀筆記中用“個(gè)數(shù)”來取代“維數(shù)”。
  引用:在出現(xiàn)標(biāo)準(zhǔn)庫之前,C++程序大量使用數(shù)組保存一組對象。而現(xiàn)代的C++程序則更多地使用vector來取代數(shù)組,數(shù)組被嚴(yán)格限制于程序內(nèi)部使用,只有當(dāng)性能測試表明使用vector無法達(dá)到必要的速度要求時(shí),才使用數(shù)組。
  筆記:我汗一個(gè)先!原來我只是一個(gè)“古代”的C++程序員。
  數(shù)組的定義必需指明元素的個(gè)數(shù),而且必須是“常量表達(dá)式”。這一點(diǎn)想必理解數(shù)組的人都會(huì)操作(即使弄錯(cuò)了,編譯器也會(huì)立即報(bào)錯(cuò)),但是真正去思考它的人也許不多。這里的“常量”概念是指程序在編譯階段就能求值的量。
  在C時(shí)代,我們并不會(huì)過多地理會(huì)“常量”這個(gè)概念,那是因?yàn)镃時(shí)代沒有const,而define這個(gè)東西,誰都知道它是在編譯前就直接替換的。但是到了C++時(shí)代,由于const的存在,使“常量”這個(gè)概念變得更普雜了。
  const size1 = 5;//這是個(gè)編譯時(shí)就可以求值的常量,它可以在數(shù)據(jù)的定義中使用。它的作用僅僅相當(dāng)于“define”。
  const size = getsize();//這個(gè)常量是運(yùn)行時(shí)才能求值的。
  除此之外,“常量求達(dá)式”的概念還指明這可是以一個(gè)算術(shù)式,只要編譯時(shí)能求值。如“char username[max_name_size + 1];”這種用法非常常用,因?yàn)樗梢员苊庠诙x數(shù)組時(shí)忘掉NULL。
  數(shù)組成員的初始化可以顯式指定,也可以不指定。顯式指定時(shí)指定成員的個(gè)數(shù)可以小于等于實(shí)際個(gè)數(shù),但不可以比實(shí)際個(gè)數(shù)大,如果小于,則其它元素視為未指定。對于未指定的元素的初始值,它們遵循變量的初始化原則,請看《變量初始化》一文。
  絕大多數(shù)書本在介紹“字符串”時(shí)都會(huì)提到,字符串其實(shí)是字符數(shù)組,只是因?yàn)樗鼈兲S?#xff0c;才會(huì)有專門的使用方法。本書也不例外。
  本書沒有提數(shù)組的實(shí)質(zhì),因?yàn)椤爸羔槨边€沒有進(jìn)入讀者的眼睛。
  引用:數(shù)組的顯著缺點(diǎn)在于:數(shù)組的長度是固定的,而且程序員無法知道一個(gè)給定數(shù)組的長度。
  筆記:其實(shí)這正在程序員心中的一個(gè)痛。當(dāng)我把數(shù)組作為參數(shù)傳送給函數(shù)時(shí),函數(shù)該怎么處理這個(gè)東西?要么是對大小有個(gè)事先的約定——這樣的程序?qū)⑹ズ芏嗤ㄓ眯?#xff0c;要么連大小一起傳遞給人家。
?
?
標(biāo)題::C++標(biāo)準(zhǔn)庫,想說愛你不容易
第三章就這樣結(jié)束了,本章介紹了三個(gè)標(biāo)準(zhǔn)庫類型:string、vector和bitset。
  可惜的是,整個(gè)第三章我都是草草讀過的。一方面因?yàn)樗鼈儾粚儆趪?yán)格意義上的C++內(nèi)容,另一方面C時(shí)代的東西在不經(jīng)意間抵觸著它們。
  確切地說,它們C時(shí)代的那些東西的替代品。它們存在的理由就是它們更優(yōu)秀。然而優(yōu)秀是一回事,動(dòng)不動(dòng)心又是一回事。
  C語言在類與對象方面的缺失,使C程序員更多地掌握了底層的操作。面對C++標(biāo)準(zhǔn)庫中的string和bitset這些東西,C程序員們都知道,在C++出來以前自己是怎樣想方法解決過問題的。刻苦才有刻骨銘心,轉(zhuǎn)到C++以后,是使用更簡單安全的標(biāo)準(zhǔn)庫,還是使用自己曾熟悉的老辦法,這是一個(gè)取舍的問題。
  引用:程序員應(yīng)優(yōu)先使用標(biāo)準(zhǔn)庫類類型。
  筆記:本書在這里放置了這樣一個(gè)提示,大概是想告誡我這樣的頑固派:“別再死糾著陳腐舊套不放了,回頭吧。”其實(shí),早在本書的前言就有了類似的內(nèi)容??墒?#xff0c;我依然不能讓自己靜下心來細(xì)讀并熟記第三章。
  也許有一天我會(huì)回頭重讀第三章,當(dāng)然,也許永遠(yuǎn)不會(huì)。因?yàn)橄駍tring和vector這樣的東西,在MFC中還有更好的替代品。
?
?
標(biāo)題::標(biāo)準(zhǔn)庫bitset類型
每當(dāng)使用到布爾變量數(shù)組時(shí),總是有點(diǎn)心疼。因?yàn)椴紶栕兞恐恍枰?和1兩種值,然而編譯器動(dòng)輒使用一個(gè)字節(jié)——甚至四個(gè)字節(jié)來存放一個(gè)布爾變量。面對1/32的使用效率,叫人怎能不心疼?
  要想節(jié)約空間也不是沒有辦法,代價(jià)是寫更多的代碼:用“&”操作將變量的某一個(gè)bit取出來,一個(gè)字節(jié)就可以存放8個(gè)布爾變量。但是,這個(gè)代價(jià)是比較重的,重到足以讓程序員望而生畏的地步。
  bitset應(yīng)運(yùn)而生,它可以方便地管理一系列的bit位而不用程序員自己來寫代碼。
  更重要的是,bitset除了可以訪問指定下標(biāo)的bit位以外,還可以把它們作為一個(gè)整數(shù)來進(jìn)行某些統(tǒng)計(jì),如:
  b.any();//b中是否存在置為1的二進(jìn)制位?
  b.count();//b中置為1的二進(jìn)制位的個(gè)數(shù)
  ……
  不過,話說回來,我還是不習(xí)慣用bitset,原因在于我是從C語言轉(zhuǎn)到C++的。詳細(xì)問題留到后一篇文章中討論。
?
?
標(biāo)題::迭代器:指針與數(shù)據(jù)庫雜交的后代
迭代器與數(shù)據(jù)庫的相似之處在于end()函數(shù)返回值為“指向末元素的下一個(gè)”。跟數(shù)據(jù)記錄集的eof這么相似。話說回來,熟練于C/C++的程序員一定不會(huì)忘了,利用下標(biāo)訪問數(shù)組時(shí)用的總是用“半開半閉區(qū)間”。就拿“int a[10]; for(int i=0; i!=10; i++)”來說,下標(biāo)為10就可以視為“最后一個(gè)元素的下一個(gè)”。只是以前不會(huì)有這么明顯的思考。
  迭代器與指針的相似之處在于它的“解引操作符”,居然就是一個(gè)“*”號。而且存在著“ivec[n]”和“*ivec”這兩個(gè)完全等價(jià)的操作。而且還支持算術(shù)運(yùn)算來移動(dòng)要訪問的元素。
  迭代的const用法與指針有個(gè)區(qū)別:
  “vector<int>::const_iterator ivec = vec.begin();”定義的ivec并不是常量,只是它指向的元素會(huì)得到保護(hù)。如果要定義本身為const的迭代器,要用“const vector<int>::ivec = vec.begin();”。
  指針是這樣處理的:
  const int *p = &i;//p指向的變量是const
  int* const p = &i;//p是const
  地雷:任何改變vector長度的操作都會(huì)使已存在的迭代器失敗。例如,在調(diào)用push_back之后,就不能再信賴指向vector的迭代器的值了。
  筆記:我不得不相信所謂的迭代器其本質(zhì)就是一個(gè)指針了。因?yàn)関ector支持動(dòng)態(tài)增長,而且保證內(nèi)存的連續(xù)。所以,每次改變它的長度都會(huì)導(dǎo)致釋放已有內(nèi)存、重新申請內(nèi)存。指針當(dāng)然得失效。
?
?
標(biāo)題::for語句的條件思考
對于for語句,我?guī)缀蹩偸沁@樣寫的:“for(int i=0; i<Max; i++);”。但是,按本書的說法,我這樣寫似乎同時(shí)犯了兩個(gè)錯(cuò)誤。
  1、本書中寫for語句中的第二個(gè)表達(dá)式(條件表達(dá)式)時(shí)總是用!=,而不用<。這幾天來雖然心里覺得奇怪,但是一直沒去思考這里面的含義。本書沒有急著告訴我“所以然”,只是提醒我讀完本書的第二部分后就會(huì)明白。我等著吧:)
  2、我總是覺得用Max這樣一個(gè)變量去代替某個(gè)需要用函數(shù)才能返回的值可以增加運(yùn)行效率,但是本書的建議與我的理解相反。它建議用“i<ivec.size()”,“因?yàn)閿?shù)據(jù)結(jié)構(gòu)可以動(dòng)態(tài)增長,……如果確實(shí)增加了新元素的話,那么測試已保存的size值作為循環(huán)結(jié)束條件就會(huì)有問題,因?yàn)闆]有將新加入的元素計(jì)算在內(nèi)。”
  同時(shí),本書為了打消運(yùn)行效率的顧慮,還提到了“內(nèi)聯(lián)函數(shù)”這個(gè)概念?,F(xiàn)在還沒有到介紹內(nèi)聯(lián)的時(shí)候,但是C++必須是一個(gè)有機(jī)體,在講述某一個(gè)知識點(diǎn)的時(shí)候,不可能完全避免另一個(gè)知識點(diǎn)。所以,我還是建議初學(xué)者不要急著閱讀本書。
?
?
標(biāo)題::標(biāo)準(zhǔn)庫vector類型
終于讓“類模板”上場了,可惜的是,在本書的第三章,還不能徹底讓類模板浮出水面,只能將就著提一下。
  引用:使用類模板可以編寫一個(gè)類定義或函數(shù)定義,而用于多個(gè)不同的數(shù)據(jù)類型?!璿ector并不是一種數(shù)據(jù)類型,而只是一個(gè)類模板,可用來定義任意多種數(shù)據(jù)類型。
  筆記:“vector<int> ivec;”中,“vector<int>”是一個(gè)數(shù)據(jù)類型,C++支持類模板,以后大量接觸類模板時(shí),這個(gè)一定要時(shí)刻注意。
  引用:在元素值已知的情況下,最好是動(dòng)態(tài)地增加元素?!m然可以對給定元素個(gè)數(shù)的vector對象預(yù)先分配內(nèi)存,但是更有效的方法是先初始化一個(gè)空的vector對象,然后再動(dòng)態(tài)地增加元素。
  將vector與string對比,可以輕松地記住empty()、size()函數(shù)和[]、=、==、!=等運(yùn)算符。不過這似乎有個(gè)前提:對C語言比較熟并且擯棄VB的String變量類型。因?yàn)?#xff0c;string雖然是一個(gè)變量,但是如果缺少對“char []”的理解,將注定不能理解它?!?#xff0c;我很反對某些人說的“可以不學(xué)C語言直接學(xué)C++”論調(diào)。
?
?
標(biāo)題::標(biāo)準(zhǔn)庫string類型
習(xí)慣了VC++的CString類,而此前用的又是C語言,所以,壓根沒有看一眼string?,F(xiàn)在既然書中專門講它,我就看一看吧。
  定義與初始化:
  string s1;
  string s2(s1);
  string s3("value");
  string s4(n, 'c');//由n個(gè)c組成的一串
  string對象的輸入除了可以“cin >> s1;”以外,還可以將cin和string對象一起作為getline()函數(shù)的參數(shù)“getline(cin, s1);”,而且這個(gè)函數(shù)的返回值還是cin。
  除此之外,string類還有empty()、size()等函數(shù)和[]、+、=、==等運(yùn)算符。
  地雷:empty()函數(shù)的功能并不是將對象置空,而是測試是否為空。這可是與CString類的Empty()函數(shù)不一樣的哦!
  本書還詳細(xì)介紹了empty::size_type類型存在的原因。在使用VC++.NET的時(shí)候,我已經(jīng)見過了size_t類型——strlen()函數(shù)的返回值就是size_t類型對象。當(dāng)時(shí)我也沒有細(xì)究這個(gè)東西,想來應(yīng)該是為了支持64位機(jī)而設(shè)的吧。不過現(xiàn)在我知道了,原來我想得還不夠。
  引用:通過這些配套類型,庫類型的使用就能與機(jī)器無關(guān)。
  關(guān)于“+運(yùn)算必須至少包含一個(gè)string類型”,這可能讓初學(xué)者摸不著頭腦。比如“s1 + s2”、“s1 + "hello"”、“"hello" + s1”是合法的,唯獨(dú)“"hello" + "world"”不合法。我在看懂“運(yùn)算符重載”之前也沒有明白這個(gè)。本書由于剛開頭,離“運(yùn)算符重載”還遠(yuǎn)著呢,所以只告訴讀者“然”、沒有告訴讀者“所以然”。我也不寫了。
  引用:下標(biāo)操作可作左值。
  筆記:人類一思考,上帝就發(fā)笑。這就是一個(gè)例證。下標(biāo)操作可作左值有什么好說的?早就用過啊?比如“char s[]="abcde"; s[2]='t';”??墒乾F(xiàn)在的不是指針變量,而是類成員,對于“string s("abcde");”來說,“s[n]”就不是簡單操作一個(gè)內(nèi)存了,而是從“[]重載函數(shù)中返回了一個(gè)值”。這個(gè)值可以做左值,并不是想當(dāng)然的事。
?
?
標(biāo)題::命名空間的using聲明
雖然實(shí)際工作中絕少用到cin和cout,但是我還是記得要用它們必先“using namespace std;”,至于為什么這樣做,三個(gè)字:不知道。
  本書從一開頭就用到了cin和cout,但是它沒有using,而是每一次用到它們都寫成“std::cin”和“std::cout”,同時(shí)提醒說這兩個(gè)字名是來自std命名空間的。于是,我似乎明白了“using namespace std;”的作用。
  也許是C++實(shí)在太難,作者遲遲不介紹更深入的內(nèi)容,到了第一部分、第三章,還沒有打算深入using,但又不得不講一點(diǎn),于是提了這樣兩行:
using std::cin;
using std::cout;
  至此,究竟什么是命名空間,命名空間是干什么的,我還是不懂。也許書后面會(huì)提吧。
?
?
標(biāo)題::頭文件
頭文件的用處主要是代碼重用——重用不僅僅是為了減少工作量,還可以保證每一次重用都是完全相同的內(nèi)容。
  正因?yàn)轭^文件可以多次重用,所以要防止有些只能出現(xiàn)一次的代碼放進(jìn)頭文件中。比如變量的定義只能有一次,聲明(含extern且不含初始化)卻可以有多次。函數(shù)也是。
  引用:一些const對象定義在頭文件中。
  筆記:看到這里,總算想通了前面的困惑:為什么const常量的作用域僅為一個(gè)文件。正如我前面的估計(jì),const常量是不開劈內(nèi)存空間的,代碼在編譯的時(shí)候就被直接替換成常量值。而且,編譯器對多個(gè)CPP是分開編譯的。所以,它必須要編譯的時(shí)候知道該常量的值。如果常量的作用域也是全局的,那么我告訴編譯器“該常量的值在另一個(gè)CPP中”將使其無可適從。
  避免頭文件被重復(fù)包含是個(gè)比較有岐義的說法,頭文件既然可以被多次包含,為什么又要避免重復(fù)包含?還是因?yàn)镃PP文件的單獨(dú)編譯。在編譯任一個(gè)CPP文件時(shí),都要知道文件的內(nèi)容,所以,如果兩個(gè)CPP都包含了同一個(gè)頭文件,那么頭文件就要被編譯兩次。但是同一個(gè)CPP如果重復(fù)調(diào)用——甚至可能循環(huán)調(diào)用——了某一個(gè)頭文件,則要及時(shí)避免。#ifndef...#define...#endif可以起到這個(gè)作用。
  對了,我一直沒想通VC++.NET的“#pragma once”是怎么工作的。它為什么不需要用變量來標(biāo)記不同的頭文件?為什么只需要一行也能標(biāo)記出整個(gè)頭文件的所有內(nèi)容?
  第一部分、第二章結(jié)束。
?
?
標(biāo)題::class與struct
首次考慮class與struct的關(guān)系源自我對類對象占用內(nèi)存數(shù)的觀察。我發(fā)現(xiàn)VC++6的CString——這么強(qiáng)大的類——它占內(nèi)存居然是4字節(jié)(sizeof(CString)為4)。那時(shí)我就認(rèn)為,類對象僅僅在內(nèi)存中存放成員變量(《C++ Primer》稱作“數(shù)據(jù)成員”)而不存放成員函數(shù)。后來,讀林銳博士的《高質(zhì)量C/C++編程指南》時(shí),才看到了比較正規(guī)的說法:C++中class與struct沒有本質(zhì)的區(qū)別。——當(dāng)時(shí)我將這句話給我朋友看時(shí),他還表現(xiàn)出不相信的神色。
  讀《C++ Primer》時(shí),我已經(jīng)熟知了class與struct的關(guān)系。但是我還是細(xì)細(xì)地沒有放過書中的任何一個(gè)字,還是作點(diǎn)記錄吧:
  引用:用class和struct關(guān)鍵字定義類的唯一差別在于默認(rèn)訪問級別:默認(rèn)情況下,struct的成員為public,而class的成員為private。
  筆記:不過,一般情況下公司與公司間規(guī)定協(xié)議時(shí),喜歡將類定義寫成struct,我想這可能是源于程序員從C語言繼承來的習(xí)慣,還有就是協(xié)議內(nèi)容一般只包含數(shù)據(jù),不包含函數(shù),也沒有必要規(guī)定安全的訪問級別。
  引用:編程新手經(jīng)常會(huì)忘記類定義后面的分號,這是個(gè)很普通的錯(cuò)誤!
  筆記:書中將這段文字標(biāo)作一個(gè)地雷,我還是引用一下吧。
?
?
標(biāo)題::枚舉
枚舉是我向來不太喜歡用的東西,幾乎我見過的每本書都是這樣介紹枚舉的:
  enum weekday {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
  我看到這里,總是想:多浪費(fèi)啊,與其這樣,還不如直接用0-6這些數(shù)呢。以后要寫“weekday Today = Sunday;”,哪有“int Today = 0;”舒服。
  本書似乎早看透了我的心理,于是,講枚舉不從枚舉入手,偏從const常量入手:
  引用:
  const int input = 0;
  const int output = 1;
  const int append = 2;
  雖然這種方法也能奏效,但是它有個(gè)明顯的缺點(diǎn):沒有指出這些值是相關(guān)聯(lián)的。枚舉提供了一種替代方法,不但定義了整數(shù)常量集,而且還把它們聚集成組。
  筆記:大師就是大師,他們寫書能切中要害,讓讀者明白標(biāo)準(zhǔn)制定者的苦心?! ?br />  另外,本書在這兒冷不丁地提了一個(gè)冷冰冰的概念:常量表達(dá)式。
  引用:常量表達(dá)式是編譯器在編譯時(shí)就能夠計(jì)算出結(jié)果的整型表達(dá)式。整型字面值常量是常表達(dá)式,……
  筆記:讓我先汗一個(gè)。常量表達(dá)式必需是整數(shù)?我怎么不知道?那“double pi = 3.14159;”后面的字面值不屬于常量表達(dá)式嗎?這是個(gè)疑問,先記下來。
  引用:枚舉類型的對象的初始化或賦值,只能通過其枚舉成員或同一枚舉類型的其它對象來進(jìn)行。
  筆記:這跟現(xiàn)實(shí)生活中的“做人要專一”有點(diǎn)相似,呵呵。簡單地說,你選擇了用名字來代替數(shù)值,那就得始終如一地使用名字,不可以用數(shù)值或其它表達(dá)式。比如“weekday Today = Sunday;”不可寫成“weekday Today = 0;”,雖然Sunday就是0。
?
?
標(biāo)題::typedef
長期以來,我一直在疑惑:typedef這個(gè)詞要它干什么?因?yàn)闆]有它我照樣可以完成所有任務(wù)。而有了它我反而覺得無法適應(yīng)。比如“UINT i;”,為什么不寫作“unsigned int i;”?本書用簡短的三句話告訴我它存在的意義:
  引用:typedef通常被用于以下三種目的:為了隱藏特定類型的實(shí)現(xiàn),更強(qiáng)調(diào)使用類型的目的;簡化復(fù)雜的類型定義,使其更易理解;允許一種類型用于多個(gè)目的,同時(shí)使得每次使用該類型的目的明確。
  筆記:第三種目的對我的啟發(fā)特大。以后就“typedef unsigned int age;”,呵呵。
?
?
標(biāo)題::引用
引用是C++的特色,一般用在函數(shù)的參數(shù)中。按有些書本的說法,叫“普通變量的用法,指針變量的效果”。書中本節(jié)沒有講訴引用在函數(shù)參數(shù)中的用法,只提了“給變量起個(gè)別名”這一個(gè)用處(畢竟本書才開頭)。說實(shí)在的,如果撇開函數(shù)參數(shù),還真想不到引用有什么用處。
  引用這個(gè)概念本身也不難理解(除了對C程序員來說有些不習(xí)慣以外),但是引用的符號卻增加了理解它的難度,我經(jīng)常在論壇上看到有初學(xué)者對“&”和“*”兩個(gè)符號的疑惑,他們問的問題可以說非?;A(chǔ),但卻表現(xiàn)出了這個(gè)問題的難以理解的特點(diǎn):
  C語言中的指針已經(jīng)夠復(fù)雜的了,加再上一個(gè)引用,引用與指針有著千絲萬縷的聯(lián)系,這就算了,而且還用了“&”這個(gè)符號。真讓初學(xué)者忙昏了頭。呵呵。下面四行程序,用到了兩個(gè)“&”和兩個(gè)“*”,但是它們的意義卻全然不同:
int a;
int &b = a;//&用在定義中僅表示變量的性質(zhì)為引用
int *c = &a;//*用在定義中僅表示變量的性質(zhì)為指針,&用在表達(dá)式中表示取地址
int d = *c;//*用天表達(dá)式中表示取指針變量所指的變量的值
  寫下以上文字,我覺得有些越權(quán)了。這些內(nèi)容估計(jì)在本書后面會(huì)詳談的,我心急了點(diǎn)。
?
?
標(biāo)題::const常量的作用域僅為一個(gè)CPP文件
如果將變量定義放在任何{}的外面,則該變量是全局的,這個(gè)規(guī)則不適用于const常量。
  以前雖然心里隱隱約約有這個(gè)感覺,但是從未正面考慮過這個(gè)問題。之所以隱隱約約有此感覺,是因?yàn)槲艺J(rèn)為編譯器并不為const常量開劈內(nèi)存空間。
  我曾經(jīng)專門做過測試:程序如下:
const int i = 5;
int *p;
p = (int *)&i;
cout << *p << "/t" << i << endl;
(*p)++;
cout << *p << "/t" << i << endl;
  測試結(jié)果發(fā)現(xiàn)const常量也是可以通過某些途徑改變其值的,但是改變不起作用。我的解釋是,編程器在生成機(jī)器碼時(shí)將所有的i直接替換成了5。使得上面兩個(gè)cout語句都成了“cout << *p << "/t" << 5 << endl;”。
  回想起以前做過的測試,便不難理解“const常量的作用域僅僅為定義它的CPP文件”,因?yàn)榫幾g器是對每個(gè)CPP文件單獨(dú)編譯的,只有在連接時(shí)才會(huì)去理會(huì)CPP之間的關(guān)系。雖然本書才看了個(gè)開頭,書中還說“我們將會(huì)在2.9.1節(jié)看到為何const對象局部于文件創(chuàng)建”。我不打算跳躍式地閱讀本書,所以,我還是先保留我自己的理解吧。
  const常量也還是可以成為全局常量的,方法是在定義的時(shí)候就加上extern。看到這里,我終于明白了《extern的困惑》中的困惑:原來,那種“有些多余,而且增加了出錯(cuò)的可能性”的做法在常量的處理上派上了用場。
?
?
標(biāo)題::變量的作用域
作用域這個(gè)概念是程序員都耳熟能詳?shù)闹R點(diǎn)。這部分知識我?guī)缀蹩梢蕴^,不過我還是認(rèn)真閱讀了相關(guān)內(nèi)容。閱讀過程中還是有體會(huì)的:
  有無數(shù)書本曾經(jīng)提醒過我:少用(盡量不用)全局變量,多用局部變量。其實(shí),即使是局部變量,也還有作用域大小的,局部變量的作用域也是越小越好。原因自然和少用全局變量一個(gè)道理。正如書中所言:“通常把一個(gè)對象定義放在它首次使用的地方是一個(gè)很好的辦法?!?br />  以往,我使用局部變量總是把它放在函數(shù)的開頭,表示這些變量在本函數(shù)中起作用。唯一的例外是for語句的循環(huán)變量(for (int i=0; i<Max; i++);)。以后我就改改,把局部變量的作用域縮小到僅僅用到它的語句塊。
?
?
標(biāo)題::extern的困惑
extern用來告訴程序:你不用為我的變量開劈內(nèi)存空間,你只要知道這個(gè)變量別處已經(jīng)聲明過了。所以,我總是在程序包含多個(gè)CPP文件時(shí)才這樣用:
  1、在某一個(gè)CPP文件中直接定義變量,如int i = 0;
  2、其它CPP文件中聲明變量,如extern int i;
  但是,書中介紹exturn還可以用來定義,如:extern double pi = 3.1416;特點(diǎn)是該extern語句包含變量的初始化。
  我覺得C++標(biāo)準(zhǔn)這樣做有些多余,而且增加了出錯(cuò)的可能性。因?yàn)椤癳xtern double pi = 3.1416;”完全可以用“double pi = 3.1416;”來代替,這樣做可以讓定義與聲明劃清界線。畢竟定義只能有一次,而聲明可以無數(shù)次。如果沒有這個(gè)特性,可以讓程序員簡單記為“不帶extern的只能有一次,帶extern的可以有無數(shù)次,而且extern同時(shí)不能指定初始值?!边@一特性的支持,使原本簡單的規(guī)則變得復(fù)雜,但沒有帶來靈活(眾所周知,C++的復(fù)雜是以高度靈活為補(bǔ)嘗的)。
  這個(gè)段落還讓我認(rèn)識到了我以前使用extern的不足。我以往在同一個(gè)CPP文件中只使用一次extern,所以我往往是在文件頭部用extern語句來聲明一下變量,這樣做雖然沒有什么錯(cuò),但卻會(huì)導(dǎo)致上下翻查:有時(shí)在文件的某一處用到變量時(shí),想看一下它的聲明,不得不把滾動(dòng)條拖到頂上去查看。如果在用到它的段落開頭處再聲明,明顯比頂部聲明要好一些。
?
?
標(biāo)題::變量初始化
int ival(1024);//直接初始化
  int ival = 1024;//復(fù)制初始化
  以前的我常用第二種用法,原因很簡單:從來沒見過第一種用法。直到后來學(xué)習(xí)了林銳博士的《高質(zhì)量C/C++編程指南》。
  那本書在講類的構(gòu)造時(shí)說道:CMyClass b = a;這種形式看起來像賦值,實(shí)際上調(diào)用的是拷貝構(gòu)造函數(shù)。
  那本書給我的感覺僅僅停留在類變量的初始化中,一直沒有過渡到內(nèi)置變量類型。直到后來,我在用VC++.NET的向?qū)Чδ芫幊绦驎r(shí),才發(fā)現(xiàn)向?qū)臀耶a(chǎn)生了類似于“int i(100);”這種語法來初始化。
  本書重點(diǎn)強(qiáng)調(diào):初始化不是賦值,
  引用:當(dāng)定義沒有初始化的變量時(shí),系統(tǒng)有時(shí)候會(huì)幫我們初始化變量。這時(shí),系統(tǒng)提供什么樣的值取決于變量的類型,也取決于變量定義的位置。……內(nèi)置類型變量是否初始化取決于變量定義的位置。在函數(shù)體外定義的變量都初始化為0,在函數(shù)體內(nèi)定義的內(nèi)置類型變量不進(jìn)行自動(dòng)初始化。……(類類型)通過定義一個(gè)特殊的構(gòu)造函數(shù)即默認(rèn)構(gòu)造函數(shù)來實(shí)現(xiàn)的。這個(gè)構(gòu)造函數(shù)被稱作默認(rèn)構(gòu)造函數(shù),是因?yàn)樗恰澳J(rèn)”運(yùn)行的?!还茏兞吭谀睦锒x,默認(rèn)構(gòu)造函數(shù)都會(huì)被使用。
  筆記:林銳博士的《高質(zhì)量C/C++編程指南》中說,如果類沒有定義無參數(shù)構(gòu)造函數(shù)或拷貝構(gòu)造函數(shù),系統(tǒng)會(huì)自動(dòng)產(chǎn)生這兩個(gè)構(gòu)造函數(shù),它們采用最簡單的“值傳遞”和“位拷貝”來完成構(gòu)造。
?
?
標(biāo)題::變量和變量名
引用:對象是內(nèi)存中具有類型的區(qū)域。
  筆記:這句話說得很直白,也只有這樣面向C++熟練工的書才可以這樣說,畢竟初學(xué)者不知道內(nèi)存與變量的關(guān)系,或者還沒考慮到。
  引用:C++還保留了一些詞用作各操作符的替代名。這些替代名用于支持某些不支持標(biāo)準(zhǔn)C++操作符號集的字符集。它們也不能用作標(biāo)識符(此處指變量名,偷貓標(biāo))。
  一般的書只提到C++變量名不可以使用關(guān)鍵字,本書還額外提了這樣一句,然后列出一個(gè)表,有and、bitand、compl、not_eq、or_eq、xor_eq、and_eq、bitor、not、or、xor。不過據(jù)我在VC++.NET上測試,這些是可以用作變量標(biāo)識符的。
  都說變量名可以含“_”,還可以用“_”開頭,但我一直沒有試過光光用一個(gè)“_”來做變量名,正好習(xí)題里有,我就試了一下,果然可以的。
?
?
標(biāo)題::cout << (wchar_t類型變量)體驗(yàn)
《C++ Primer》說了,字符常量或字符串常量前加L,表示wchat_t類型,于是我試了一下:
程序如下:
char a = "a";
wchar_t b = L"a";
cout << a << endl;
cout << b << endl;
結(jié)果如下:
a
0012FEBC
暈,怎么出現(xiàn)這個(gè)結(jié)果?
讓我再試。
程序如下:
char a = 'a';
wchar_t b = L'a';
cout << a << endl;
cout << b << endl;
結(jié)果如下:
a
97
由此可見,cout的<<運(yùn)算符沒有對wchat_t的重載(或不健全)。
?
?
?
標(biāo)題::內(nèi)置類型之精度選擇
引用:……大多數(shù)通用機(jī)器都是使用和long類型一樣長的32位來表示int類型。整型運(yùn)算時(shí),用32位表示int類型和用64位表示long類型的機(jī)器會(huì)出現(xiàn)應(yīng)該選擇int類型還是long類型的難題。在這些機(jī)器上,用long類型進(jìn)行計(jì)算所付出的運(yùn)行時(shí)代價(jià)遠(yuǎn)遠(yuǎn)高于用int類型進(jìn)行同樣計(jì)算的代價(jià)?!瓫Q定使用哪種浮點(diǎn)型就容易多了:使用double類型基本上不會(huì)有錯(cuò)。在float類型中隱式的精度損失是不能忽視的,而double類型精度代價(jià)相對于float類型精度代價(jià)可以忽略。事實(shí)上,有些機(jī)器上,double類型比float類型的計(jì)算要快和多。long double類型提供的精度通常沒有必要,而且還需要承擔(dān)額外的運(yùn)行代價(jià)。
?
?
標(biāo)題::內(nèi)置類型之int和bool
第一部分,第二章
  引用:C++標(biāo)準(zhǔn)規(guī)定了每個(gè)算術(shù)類型的最小存儲空間,但它并不阻止編譯器使用更大的存儲空間,事實(shí)上,對于int類型,幾乎所有的編譯器使用的存儲空間都比所要求的大。
  筆記:確實(shí)如此,VC++中int和long是一樣大。VC++.NET增加了對_int64的支持。
  引用:字符類型有兩種:char和wchar_t,wchar_t類型用于擴(kuò)展字符集,比如漢字和日語。
  筆記:我怎么不知道wchar_t?我自己用包含漢字的字符串時(shí)用的也是char。:(
  看到bool型,我心里對VC++有些氣憤。因?yàn)閂C++里有一個(gè)BOOL宏。它的原型為“typedef int BOOL”。既然C++標(biāo)準(zhǔn)已經(jīng)有bool型,VC++加入BOOL的用意很明顯:迎合更多的編程習(xí)慣。但是,即使非要增加對BOOL的支持,我認(rèn)為原型應(yīng)該這樣:“typedef bool BOOL”,這樣更易于理解。
  當(dāng)然了,長期以來我一直沒有注意到bool確實(shí)也不應(yīng)該。但是正是BOOL的存在,阻礙了我對bool的理解。
?
?
標(biāo)題::第一章:快速入門
第一章:快速入門
  本章的存在使本書變得不像一本“規(guī)范書”,似乎成了“入門書”,這可能是后來版本新加入的內(nèi)容。以至于這一章節(jié)被排除在任何一個(gè)“部分”之外。
  本章“無厘頭”地簡要介紹了cin、cout、注釋、while、for、if等概念。這么多東西,每一個(gè)都介紹點(diǎn)皮毛,然后組合成一個(gè)綜合實(shí)例。
  我稱其為“無厘頭”有以下原因:如果本書面對不了解C++的讀者,那么這一章似乎是有用的,但是C++的入門者使用本書顯然很難入門,我不了解國外的情況怎樣,至少我身邊的人是這樣;如果本書面對已經(jīng)了解C++的讀者,那么,這些東西都不用介紹,讀者也可以看懂那個(gè)“綜合實(shí)例”,而且所謂的“綜合實(shí)例”也沒有存在的必要。
不過有一個(gè)小小的收獲:
int main()
{
? return -1;
}
如果返回值為-1,Windows的CMD中運(yùn)行也沒有任何額外信息,說明Windows并不報(bào)告運(yùn)行失敗。
?
標(biāo)題::《〈C++ Primer〉閱讀筆記》前言
在讀本書之前,我已經(jīng)有過一段編寫C++程序的歷史,如果連C語言也算在內(nèi),可以追溯到十年前。用BASIC語言編程序的歷史則有十四年(1992-2006)。
  長期編程序中所使用的參考書無非有兩種:介紹算法的書和介紹語法的書。我所買的參考書往往是同時(shí)介紹兩者的。而對語法的介紹,則只是基于某一個(gè)編譯器。
  于是,這十年來,我所學(xué)習(xí)的“C/C++”,從本質(zhì)上說只是Turbo C和Visual C++,對C/C++本身的理解也是被編譯器過濾的內(nèi)容。不是我不想去了解C/C++的本質(zhì),只是我對C/C++的“法典”有著與生俱來的恐懼。
  這個(gè)恐懼直到我發(fā)現(xiàn)了《C++ Primer中文版》,當(dāng)我捧起這本C++的“圣經(jīng)”時(shí),我終于能理解為什么每有幾十萬人冒著被踩死的危險(xiǎn)前去朝圣。
  請?jiān)试S我用“圣經(jīng)”來比喻這本書,我知道這樣并不合適,因?yàn)榻^大多數(shù)中國人并不知道“圣經(jīng)”的地位,但是我搜遍大腦的每一個(gè)角落也找不到其它合適的比喻。這源于中國人缺乏信仰。
  在半年前,我曾經(jīng)帶著無限的敬仰閱讀了林銳博士的《高質(zhì)量C/C++編程指南》,并且及時(shí)培養(yǎng)/修正了我的編程習(xí)慣。當(dāng)然了,正如《C++ Primer》所言:“什么是C或C++程序的正確格式存在著無休止的爭論……”。所以,我所修正的只是“自由體”,而不是與林銳矛盾的方面。令我感到欣慰的是,《C++ Primer》居然也用一定的筆默來講格式與風(fēng)格,不同的是,它同時(shí)介紹幾種風(fēng)格,然后作出一個(gè)略帶傾向性的建議。同時(shí),書中還告誡讀者:“一旦選擇了某種風(fēng)格,就要始終如一地使用?!?br />  從現(xiàn)在起,我就要捧起這一本四五厘米厚、七百多頁的圣經(jīng),在閱讀過程中,難免會(huì)有重點(diǎn)、要點(diǎn)要記錄。我比較愛書,不愿在書上做標(biāo)記,只好選擇了BLOG這種形式來做讀書筆記。
?

本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/hukeab/archive/2008/09/15/2933224.aspx

總結(jié)

以上是生活随笔為你收集整理的C++ Primer读书笔记(从后向前看)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

自拍偷自拍亚洲精品被多人伦好爽 | 少妇被粗大的猛进出69影院 | 高清无码午夜福利视频 | 人妻少妇被猛烈进入中文字幕 | 国产在线精品一区二区三区直播 | 国产精品无套呻吟在线 | 国产欧美亚洲精品a | 97久久精品无码一区二区 | 久久97精品久久久久久久不卡 | 亚欧洲精品在线视频免费观看 | 国产福利视频一区二区 | 精品国产福利一区二区 | 成人影院yy111111在线观看 | 国产午夜福利100集发布 | 欧美丰满老熟妇xxxxx性 | 无码av最新清无码专区吞精 | 久久久久se色偷偷亚洲精品av | 免费无码午夜福利片69 | 国产办公室秘书无码精品99 | 性色av无码免费一区二区三区 | 亚洲码国产精品高潮在线 | 中文字幕无码免费久久9一区9 | 亚洲一区二区三区含羞草 | 成人无码精品1区2区3区免费看 | 国产亚洲欧美在线专区 | 精品国产一区二区三区四区在线看 | 日本乱人伦片中文三区 | aⅴ在线视频男人的天堂 | 一个人看的www免费视频在线观看 | 久久www免费人成人片 | 装睡被陌生人摸出水好爽 | 思思久久99热只有频精品66 | 午夜无码人妻av大片色欲 | 亚洲精品久久久久中文第一幕 | 国内精品一区二区三区不卡 | 人人妻人人澡人人爽人人精品 | 丁香花在线影院观看在线播放 | 性欧美疯狂xxxxbbbb | 午夜精品一区二区三区在线观看 | 樱花草在线播放免费中文 | 亚洲熟妇色xxxxx欧美老妇 | 国产精品99爱免费视频 | 99久久99久久免费精品蜜桃 | 蜜臀aⅴ国产精品久久久国产老师 | av无码久久久久不卡免费网站 | 无码精品国产va在线观看dvd | 精品国产乱码久久久久乱码 | 麻豆国产丝袜白领秘书在线观看 | 国产精品亚洲专区无码不卡 | 久久精品国产大片免费观看 | 久久国产36精品色熟妇 | 久久熟妇人妻午夜寂寞影院 | 久久久www成人免费毛片 | 国产97色在线 | 免 | 精品人妻人人做人人爽夜夜爽 | 亚拍精品一区二区三区探花 | 国产精品手机免费 | 天天爽夜夜爽夜夜爽 | 久久人人97超碰a片精品 | 亚洲色大成网站www国产 | 全球成人中文在线 | 精品国产av色一区二区深夜久久 | 无码国内精品人妻少妇 | 亚洲精品一区二区三区在线观看 | 婷婷五月综合激情中文字幕 | 人妻少妇精品视频专区 | 日韩精品久久久肉伦网站 | 亚洲乱码国产乱码精品精 | 国产精品久久国产精品99 | 激情内射日本一区二区三区 | 无码中文字幕色专区 | 99久久99久久免费精品蜜桃 | 成人无码影片精品久久久 | 欧美一区二区三区 | 成人无码精品1区2区3区免费看 | 伊人久久大香线焦av综合影院 | 无码人妻丰满熟妇区毛片18 | 中文字幕人成乱码熟女app | 欧美野外疯狂做受xxxx高潮 | 六月丁香婷婷色狠狠久久 | 国产色视频一区二区三区 | 欧美日本免费一区二区三区 | 久久亚洲a片com人成 | 亚洲毛片av日韩av无码 | 日本一区二区三区免费高清 | 粗大的内捧猛烈进出视频 | 成人aaa片一区国产精品 | 噜噜噜亚洲色成人网站 | 人妻无码αv中文字幕久久琪琪布 | 久久午夜无码鲁丝片午夜精品 | 国产偷国产偷精品高清尤物 | 精品熟女少妇av免费观看 | 中文字幕+乱码+中文字幕一区 | 少妇被黑人到高潮喷出白浆 | 欧美人与动性行为视频 | 亚洲狠狠婷婷综合久久 | 天堂在线观看www | 樱花草在线播放免费中文 | 成人欧美一区二区三区黑人免费 | 成人免费视频视频在线观看 免费 | 久久亚洲中文字幕无码 | 在线观看免费人成视频 | 亚洲熟悉妇女xxx妇女av | 在线成人www免费观看视频 | 中文字幕乱码中文乱码51精品 | 亚洲成av人在线观看网址 | 俄罗斯老熟妇色xxxx | 全黄性性激高免费视频 | 一本大道久久东京热无码av | 美女黄网站人色视频免费国产 | 免费国产黄网站在线观看 | 成人亚洲精品久久久久 | 成人精品视频一区二区 | 欧美人与物videos另类 | 精品一区二区三区无码免费视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产精品久久久久久亚洲毛片 | 国产精品人人妻人人爽 | 亚洲伊人久久精品影院 | 一本久久伊人热热精品中文字幕 | 免费播放一区二区三区 | 老熟妇乱子伦牲交视频 | 国产成人精品视频ⅴa片软件竹菊 | 真人与拘做受免费视频一 | 东京热无码av男人的天堂 | 亚洲精品美女久久久久久久 | 亚洲无人区一区二区三区 | 日日碰狠狠丁香久燥 | 亚洲色成人中文字幕网站 | 无码中文字幕色专区 | 无码人妻黑人中文字幕 | 精品无码成人片一区二区98 | 国产精品美女久久久久av爽李琼 | 久在线观看福利视频 | 日本va欧美va欧美va精品 | 亚洲日韩一区二区三区 | 亚洲午夜福利在线观看 | 亚洲s码欧洲m码国产av | 无码帝国www无码专区色综合 | 国产电影无码午夜在线播放 | 亚洲色偷偷偷综合网 | 成人精品一区二区三区中文字幕 | 婷婷综合久久中文字幕蜜桃三电影 | 自拍偷自拍亚洲精品10p | 精品aⅴ一区二区三区 | 久久久久亚洲精品男人的天堂 | 精品国偷自产在线 | 国产艳妇av在线观看果冻传媒 | 国产真人无遮挡作爱免费视频 | 67194成是人免费无码 | 3d动漫精品啪啪一区二区中 | 亚洲精品成a人在线观看 | 97精品国产97久久久久久免费 | 帮老师解开蕾丝奶罩吸乳网站 | 夜夜影院未满十八勿进 | 99久久人妻精品免费一区 | 亚洲日韩精品欧美一区二区 | 97se亚洲精品一区 | 在线观看欧美一区二区三区 | 男人扒开女人内裤强吻桶进去 | 精品无码国产一区二区三区av | 亚洲熟熟妇xxxx | 99久久人妻精品免费二区 | 在线 国产 欧美 亚洲 天堂 | 伊在人天堂亚洲香蕉精品区 | 日本护士xxxxhd少妇 | 亚洲日韩精品欧美一区二区 | 中文久久乱码一区二区 | 熟妇女人妻丰满少妇中文字幕 | 欧美乱妇无乱码大黄a片 | 又湿又紧又大又爽a视频国产 | 性欧美牲交xxxxx视频 | 中文字幕亚洲情99在线 | 国产成人精品必看 | 精品久久久久久人妻无码中文字幕 | 亚洲一区二区三区偷拍女厕 | 99国产精品白浆在线观看免费 | 日本熟妇大屁股人妻 | 亚洲国产精品久久久天堂 | 欧美熟妇另类久久久久久多毛 | 久久 国产 尿 小便 嘘嘘 | 欧美人与动性行为视频 | 99久久久无码国产精品免费 | 国产午夜亚洲精品不卡 | 国产乡下妇女做爰 | 日日摸天天摸爽爽狠狠97 | 97se亚洲精品一区 | 国产 浪潮av性色四虎 | 精品国产av色一区二区深夜久久 | 蜜桃视频插满18在线观看 | 成熟人妻av无码专区 | 丁香花在线影院观看在线播放 | 乱人伦人妻中文字幕无码久久网 | 欧美成人家庭影院 | 日日鲁鲁鲁夜夜爽爽狠狠 | 亚洲精品一区二区三区大桥未久 | 国产人成高清在线视频99最全资源 | 精品日本一区二区三区在线观看 | 久久国产精品_国产精品 | 色一情一乱一伦一视频免费看 | 国产办公室秘书无码精品99 | 日韩视频 中文字幕 视频一区 | 一本精品99久久精品77 | 丁香啪啪综合成人亚洲 | 久久久久se色偷偷亚洲精品av | 无码福利日韩神码福利片 | 精品人妻人人做人人爽 | 在线视频网站www色 | 国产va免费精品观看 | 亚洲色偷偷偷综合网 | 欧美人与禽zoz0性伦交 | 人妻无码久久精品人妻 | 日韩欧美中文字幕公布 | 特大黑人娇小亚洲女 | 十八禁视频网站在线观看 | 乱码av麻豆丝袜熟女系列 | av在线亚洲欧洲日产一区二区 | 97夜夜澡人人双人人人喊 | 国产另类ts人妖一区二区 | 免费国产黄网站在线观看 | 国产精品99久久精品爆乳 | 欧美丰满熟妇xxxx | 漂亮人妻洗澡被公强 日日躁 | 国产欧美亚洲精品a | 无码国内精品人妻少妇 | 国产真人无遮挡作爱免费视频 | 亚洲欧洲日本无在线码 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 精品一区二区三区波多野结衣 | 国产综合色产在线精品 | 国产尤物精品视频 | 又粗又大又硬毛片免费看 | 成年美女黄网站色大免费全看 | 中文字幕无码人妻少妇免费 | 亚洲精品无码国产 | yw尤物av无码国产在线观看 | 麻豆成人精品国产免费 | 大屁股大乳丰满人妻 | 国产精品毛片一区二区 | 无码国产激情在线观看 | 一二三四在线观看免费视频 | 无码免费一区二区三区 | 亚洲自偷自拍另类第1页 | 色 综合 欧美 亚洲 国产 | 国产精品久久久久久久影院 | 亚洲国产精品无码一区二区三区 | 亚洲人成网站在线播放942 | 女高中生第一次破苞av | 99re在线播放 | 人人爽人人爽人人片av亚洲 | 国产9 9在线 | 中文 | 性色欲情网站iwww九文堂 | 色婷婷综合中文久久一本 | 亚洲国产精品无码久久久久高潮 | 久久久婷婷五月亚洲97号色 | 人人澡人人透人人爽 | 天堂在线观看www | 中文无码精品a∨在线观看不卡 | 97久久国产亚洲精品超碰热 | 久久人妻内射无码一区三区 | 日韩精品久久久肉伦网站 | 中文字幕无线码 | 色综合久久88色综合天天 | 国产高清不卡无码视频 | 亚洲区欧美区综合区自拍区 | aa片在线观看视频在线播放 | 国产精品久久国产精品99 | 亚洲爆乳大丰满无码专区 | 97夜夜澡人人双人人人喊 | 99国产精品白浆在线观看免费 | 蜜桃视频插满18在线观看 | 在线天堂新版最新版在线8 | 国产超级va在线观看视频 | 国产亚洲精品久久久久久大师 | 国产免费观看黄av片 | 精品国产乱码久久久久乱码 | 无码成人精品区在线观看 | 久久精品无码一区二区三区 | 国产电影无码午夜在线播放 | 精品人妻人人做人人爽夜夜爽 | 欧美 日韩 人妻 高清 中文 | 国产乱人无码伦av在线a | 久青草影院在线观看国产 | 全黄性性激高免费视频 | 男女性色大片免费网站 | 亚洲精品一区国产 | 牲欲强的熟妇农村老妇女视频 | 久久99热只有频精品8 | 人人妻人人澡人人爽精品欧美 | 老熟妇乱子伦牲交视频 | 国内揄拍国内精品少妇国语 | 精品午夜福利在线观看 | 日韩人妻无码中文字幕视频 | 精品国精品国产自在久国产87 | 国产精品人人爽人人做我的可爱 | 97人妻精品一区二区三区 | 日日碰狠狠躁久久躁蜜桃 | 亚洲精品国产精品乱码视色 | 亚洲大尺度无码无码专区 | 最近的中文字幕在线看视频 | 欧美激情一区二区三区成人 | 国内精品九九久久久精品 | 精品国精品国产自在久国产87 | 国产精品久久久一区二区三区 | 亚洲熟妇色xxxxx欧美老妇y | 亚拍精品一区二区三区探花 | 久久久亚洲欧洲日产国码αv | 无码人妻精品一区二区三区不卡 | 麻豆国产人妻欲求不满谁演的 | 免费观看的无遮挡av | 亚洲国产av精品一区二区蜜芽 | 天堂а√在线地址中文在线 | 日韩在线不卡免费视频一区 | 中文字幕无码人妻少妇免费 | 精品国产麻豆免费人成网站 | 中文精品无码中文字幕无码专区 | a片免费视频在线观看 | 成人一区二区免费视频 | 色欲久久久天天天综合网精品 | 日本精品久久久久中文字幕 | 女人被爽到呻吟gif动态图视看 | 国产熟妇高潮叫床视频播放 | 性色欲情网站iwww九文堂 | 国产乱人伦av在线无码 | 国产在线精品一区二区三区直播 | 日日摸夜夜摸狠狠摸婷婷 | 亚洲成a人片在线观看无码3d | 波多野结衣一区二区三区av免费 | 性生交片免费无码看人 | 国产成人人人97超碰超爽8 | 国产艳妇av在线观看果冻传媒 | 131美女爱做视频 | 国产午夜福利亚洲第一 | 久久久久久久人妻无码中文字幕爆 | 熟女少妇在线视频播放 | 300部国产真实乱 | 少妇人妻大乳在线视频 | 国产猛烈高潮尖叫视频免费 | 高潮喷水的毛片 | 国产精品无码永久免费888 | 狠狠色噜噜狠狠狠狠7777米奇 | 久久久精品成人免费观看 | 性生交大片免费看l | 久久久中文久久久无码 | 国产精品国产自线拍免费软件 | 精品无码成人片一区二区98 | 国产舌乚八伦偷品w中 | 伊人久久大香线焦av综合影院 | 欧美精品在线观看 | 精品久久久无码人妻字幂 | 日日干夜夜干 | 精品国精品国产自在久国产87 | 日本又色又爽又黄的a片18禁 | 亚洲爆乳精品无码一区二区三区 | 色五月丁香五月综合五月 | 久久精品一区二区三区四区 | 人妻有码中文字幕在线 | 久久久久av无码免费网 | 国产av一区二区精品久久凹凸 | 婷婷丁香六月激情综合啪 | 人人妻人人澡人人爽精品欧美 | 亚洲欧美日韩综合久久久 | 久久国产劲爆∧v内射 | 捆绑白丝粉色jk震动捧喷白浆 | 中文字幕 人妻熟女 | 麻豆人妻少妇精品无码专区 | 国产特级毛片aaaaaa高潮流水 | 欧美黑人性暴力猛交喷水 | 亚洲国产精华液网站w | 亚洲日本一区二区三区在线 | 久久久久久久久888 | 精品人人妻人人澡人人爽人人 | 131美女爱做视频 | 国内精品人妻无码久久久影院蜜桃 | 少妇邻居内射在线 | 曰韩无码二三区中文字幕 | 欧美 丝袜 自拍 制服 另类 | 亚洲国产欧美在线成人 | 精品久久综合1区2区3区激情 | 国产一区二区三区影院 | 日韩精品无码免费一区二区三区 | 老熟妇仑乱视频一区二区 | 免费乱码人妻系列无码专区 | 午夜嘿嘿嘿影院 | 亚洲精品国偷拍自产在线麻豆 | 欧美一区二区三区 | 久久综合狠狠综合久久综合88 | 综合激情五月综合激情五月激情1 | 欧洲欧美人成视频在线 | 亚洲成在人网站无码天堂 | 捆绑白丝粉色jk震动捧喷白浆 | 精品一区二区三区波多野结衣 | 成 人 网 站国产免费观看 | 亚洲成a人片在线观看无码 | 午夜福利一区二区三区在线观看 | 中文毛片无遮挡高清免费 | 亚洲精品国产a久久久久久 | 国产精品高潮呻吟av久久 | 国产熟妇高潮叫床视频播放 | 久久久www成人免费毛片 | 国产国语老龄妇女a片 | 97人妻精品一区二区三区 | 天天拍夜夜添久久精品大 | 国产婷婷色一区二区三区在线 | 精品久久久久久人妻无码中文字幕 | 久久久精品456亚洲影院 | 真人与拘做受免费视频 | 国产又爽又猛又粗的视频a片 | 国产精品多人p群无码 | 动漫av一区二区在线观看 | 青草青草久热国产精品 | 国产sm调教视频在线观看 | 女人被爽到呻吟gif动态图视看 | 欧美喷潮久久久xxxxx | 国产一区二区三区四区五区加勒比 | 久久综合激激的五月天 | 国产精品亚洲а∨无码播放麻豆 | 国产精品久久久午夜夜伦鲁鲁 | 欧美日韩综合一区二区三区 | 久久亚洲国产成人精品性色 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 狠狠色噜噜狠狠狠7777奇米 | 无码精品国产va在线观看dvd | 骚片av蜜桃精品一区 | 午夜熟女插插xx免费视频 | 亚洲人亚洲人成电影网站色 | 99国产精品白浆在线观看免费 | 伊人久久大香线焦av综合影院 | 2020久久香蕉国产线看观看 | 国产超碰人人爽人人做人人添 | 999久久久国产精品消防器材 | 日本精品人妻无码免费大全 | 欧美亚洲日韩国产人成在线播放 | 国产精品丝袜黑色高跟鞋 | 十八禁视频网站在线观看 | 久久成人a毛片免费观看网站 | 无码乱肉视频免费大全合集 | 欧美激情一区二区三区成人 | 亚洲国产欧美国产综合一区 | 亚洲日韩av片在线观看 | 欧美激情一区二区三区成人 | 久青草影院在线观看国产 | 亚洲午夜久久久影院 | 麻豆蜜桃av蜜臀av色欲av | 亚洲一区av无码专区在线观看 | 中文毛片无遮挡高清免费 | 精品午夜福利在线观看 | 欧美阿v高清资源不卡在线播放 | 午夜福利一区二区三区在线观看 | 日韩少妇白浆无码系列 | 国产内射老熟女aaaa | 亚洲精品国偷拍自产在线麻豆 | 粉嫩少妇内射浓精videos | 国产黄在线观看免费观看不卡 | 又大又黄又粗又爽的免费视频 | 国产精品第一国产精品 | 国产精品18久久久久久麻辣 | 99re在线播放 | 欧美freesex黑人又粗又大 | 麻豆国产人妻欲求不满 | 国产激情艳情在线看视频 | 精品无码国产自产拍在线观看蜜 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 国产成人人人97超碰超爽8 | 久久久久久久久蜜桃 | 亚洲aⅴ无码成人网站国产app | 强伦人妻一区二区三区视频18 | 亚洲中文字幕在线无码一区二区 | 中文无码伦av中文字幕 | 未满小14洗澡无码视频网站 | 丰满人妻一区二区三区免费视频 | 国产真实乱对白精彩久久 | 中文字幕日产无线码一区 | 午夜理论片yy44880影院 | 性做久久久久久久久 | 亚洲色欲色欲欲www在线 | 国产suv精品一区二区五 | 无码纯肉视频在线观看 | 日产国产精品亚洲系列 | 久久久久99精品国产片 | 久久人人97超碰a片精品 | 人人澡人人妻人人爽人人蜜桃 | а√资源新版在线天堂 | 久久久久久av无码免费看大片 | 内射爽无广熟女亚洲 | 中文字幕乱码人妻无码久久 | 熟女体下毛毛黑森林 | 少妇邻居内射在线 | 性开放的女人aaa片 | 中文字幕精品av一区二区五区 | 国产电影无码午夜在线播放 | 福利一区二区三区视频在线观看 | 欧美性黑人极品hd | 久久熟妇人妻午夜寂寞影院 | 天堂无码人妻精品一区二区三区 | 精品欧美一区二区三区久久久 | 色一情一乱一伦一区二区三欧美 | 狂野欧美性猛xxxx乱大交 | 久久国产自偷自偷免费一区调 | 亚洲日韩av一区二区三区四区 | 图片区 小说区 区 亚洲五月 | 夜精品a片一区二区三区无码白浆 | 亚洲成av人片天堂网无码】 | 欧美老人巨大xxxx做受 | 欧美三级不卡在线观看 | 国产精品国产自线拍免费软件 | 国产97人人超碰caoprom | 欧美日韩人成综合在线播放 | 国产福利视频一区二区 | 成熟妇人a片免费看网站 | √天堂资源地址中文在线 | 久久久www成人免费毛片 | 97无码免费人妻超级碰碰夜夜 | 久久99精品久久久久久动态图 | 麻花豆传媒剧国产免费mv在线 | 性啪啪chinese东北女人 | 国产成人精品无码播放 | 狠狠综合久久久久综合网 | 撕开奶罩揉吮奶头视频 | 亚洲熟妇色xxxxx欧美老妇y | 国产9 9在线 | 中文 | 国产一区二区三区四区五区加勒比 | 激情爆乳一区二区三区 | 最近中文2019字幕第二页 | 在线精品亚洲一区二区 | 亚洲精品欧美二区三区中文字幕 | aa片在线观看视频在线播放 | 精品日本一区二区三区在线观看 | 99久久久国产精品无码免费 | 综合激情五月综合激情五月激情1 | 国内精品久久久久久中文字幕 | 欧洲精品码一区二区三区免费看 | 亚洲aⅴ无码成人网站国产app | 一区二区传媒有限公司 | 日本精品人妻无码免费大全 | 国产欧美熟妇另类久久久 | 亚洲精品一区三区三区在线观看 | 无码人妻av免费一区二区三区 | 国产无遮挡吃胸膜奶免费看 | 一二三四社区在线中文视频 | 亚洲综合无码久久精品综合 | 丰满岳乱妇在线观看中字无码 | 精品人妻人人做人人爽 | 丝袜足控一区二区三区 | 极品尤物被啪到呻吟喷水 | 色婷婷综合中文久久一本 | 网友自拍区视频精品 | 又大又紧又粉嫩18p少妇 | 99久久久无码国产aaa精品 | 清纯唯美经典一区二区 | 野狼第一精品社区 | 女人被爽到呻吟gif动态图视看 | 亚洲日本在线电影 | 午夜无码区在线观看 | 国内丰满熟女出轨videos | 伊人久久大香线蕉午夜 | 无码人中文字幕 | 日韩欧美中文字幕在线三区 | 日韩人妻系列无码专区 | 国产xxx69麻豆国语对白 | 国产精品多人p群无码 | 亚洲成a人片在线观看日本 | 国产亲子乱弄免费视频 | 性欧美疯狂xxxxbbbb | 无码精品人妻一区二区三区av | 伊人久久大香线蕉午夜 | 国产后入清纯学生妹 | 亚洲国产精品美女久久久久 | 精品欧美一区二区三区久久久 | 国产手机在线αⅴ片无码观看 | 无码一区二区三区在线观看 | 日韩精品a片一区二区三区妖精 | 无码精品人妻一区二区三区av | 欧美人与牲动交xxxx | 蜜桃视频插满18在线观看 | 18禁止看的免费污网站 | 国产超碰人人爽人人做人人添 | 女人高潮内射99精品 | 国产精品美女久久久 | 国产超级va在线观看视频 | 中文字幕av日韩精品一区二区 | 国产在线精品一区二区三区直播 | 亚洲阿v天堂在线 | 午夜精品一区二区三区在线观看 | 国产内射老熟女aaaa | 中文字幕无线码免费人妻 | www成人国产高清内射 | 奇米影视888欧美在线观看 | 国产无遮挡又黄又爽又色 | 在线亚洲高清揄拍自拍一品区 | 一本久久a久久精品vr综合 | 久精品国产欧美亚洲色aⅴ大片 | 国产一区二区三区四区五区加勒比 | 99久久人妻精品免费二区 | 免费网站看v片在线18禁无码 | 久久人人爽人人人人片 | 精品日本一区二区三区在线观看 | 国产精品亚洲一区二区三区喷水 | 亚洲娇小与黑人巨大交 | 午夜福利试看120秒体验区 | 国产在线精品一区二区三区直播 | 野外少妇愉情中文字幕 | 国产suv精品一区二区五 | 亚洲人成人无码网www国产 | 久久97精品久久久久久久不卡 | 久久综合香蕉国产蜜臀av | 麻豆精品国产精华精华液好用吗 | 国产成人精品视频ⅴa片软件竹菊 | 亚洲色欲久久久综合网东京热 | 国产精品人人妻人人爽 | 九一九色国产 | 国产一精品一av一免费 | 久久精品女人天堂av免费观看 | 亚洲日韩av一区二区三区四区 | 国产三级久久久精品麻豆三级 | 精品国产精品久久一区免费式 | 久久精品丝袜高跟鞋 | 亚洲中文无码av永久不收费 | 思思久久99热只有频精品66 | 玩弄中年熟妇正在播放 | 亚洲精品一区二区三区在线观看 | 国产 精品 自在自线 | 国产性生大片免费观看性 | 日韩人妻无码一区二区三区久久99 | 中文字幕+乱码+中文字幕一区 | 又大又紧又粉嫩18p少妇 | 亚洲乱码日产精品bd | 一本久道久久综合狠狠爱 | 全球成人中文在线 | 久久国产精品二国产精品 | 亚洲成熟女人毛毛耸耸多 | 学生妹亚洲一区二区 | 国产精品无码一区二区桃花视频 | 激情五月综合色婷婷一区二区 | 红桃av一区二区三区在线无码av | 秋霞成人午夜鲁丝一区二区三区 | 精品久久8x国产免费观看 | 人人爽人人澡人人高潮 | 精品久久久久香蕉网 | 久久久久成人片免费观看蜜芽 | 亚洲 另类 在线 欧美 制服 | 亚洲熟妇色xxxxx欧美老妇y | 一本久道久久综合婷婷五月 | 精品久久8x国产免费观看 | 亚洲中文无码av永久不收费 | 国产无套内射久久久国产 | 无套内谢的新婚少妇国语播放 | 波多野结衣av一区二区全免费观看 | 亚洲aⅴ无码成人网站国产app | 国产成人午夜福利在线播放 | 成人无码影片精品久久久 | 国产猛烈高潮尖叫视频免费 | 日韩少妇白浆无码系列 | 日韩精品a片一区二区三区妖精 | 日韩成人一区二区三区在线观看 | 亚洲午夜无码久久 | 在线看片无码永久免费视频 | 日韩亚洲欧美中文高清在线 | 99久久精品国产一区二区蜜芽 | 色婷婷综合激情综在线播放 | 狠狠色丁香久久婷婷综合五月 | 精品无码成人片一区二区98 | 亚洲中文字幕成人无码 | 国产国产精品人在线视 | 欧美日韩色另类综合 | 亚洲一区二区三区在线观看网站 | 久久无码人妻影院 | 色噜噜亚洲男人的天堂 | 少妇无套内谢久久久久 | 欧美精品在线观看 | 国产国产精品人在线视 | 日韩精品成人一区二区三区 | 久久亚洲中文字幕无码 | 男人扒开女人内裤强吻桶进去 | 久久亚洲中文字幕无码 | 国产人妻人伦精品 | 亚洲精品无码国产 | 国产精品久久久久7777 | 图片小说视频一区二区 | 成人一区二区免费视频 | 无码av中文字幕免费放 | 亚洲国产av精品一区二区蜜芽 | 久久精品人妻少妇一区二区三区 | 亚洲人交乣女bbw | 国产香蕉尹人视频在线 | 人妻少妇精品无码专区二区 | 亚洲人成影院在线观看 | 免费网站看v片在线18禁无码 | 丰满妇女强制高潮18xxxx | 国产三级久久久精品麻豆三级 | 永久免费观看美女裸体的网站 | 亚洲中文字幕va福利 | 无码人妻精品一区二区三区不卡 | 精品欧洲av无码一区二区三区 | 东京热无码av男人的天堂 | 国产精品久久久久9999小说 | 亚洲va中文字幕无码久久不卡 | 精品国产aⅴ无码一区二区 | 99er热精品视频 | 亚洲精品国偷拍自产在线麻豆 | 波多野结衣一区二区三区av免费 | 东京热一精品无码av | 国产无套粉嫩白浆在线 | 曰韩无码二三区中文字幕 | 国产亚洲人成在线播放 | 免费人成在线视频无码 | 国产精品久久久久久无码 | 亚洲色欲色欲天天天www | 欧美性黑人极品hd | 国产成人无码午夜视频在线观看 | 久久伊人色av天堂九九小黄鸭 | 嫩b人妻精品一区二区三区 | 国色天香社区在线视频 | 国产精品久免费的黄网站 | 亚洲s色大片在线观看 | 一二三四在线观看免费视频 | 欧美变态另类xxxx | 国产免费久久久久久无码 | 人人妻人人澡人人爽欧美一区 | 日韩人妻系列无码专区 | 国产精品理论片在线观看 | 色老头在线一区二区三区 | 伊在人天堂亚洲香蕉精品区 | 永久免费精品精品永久-夜色 | 在线а√天堂中文官网 | 日韩精品无码一本二本三本色 | 无遮挡国产高潮视频免费观看 | 日日天干夜夜狠狠爱 | 99久久婷婷国产综合精品青草免费 | 久久久久久久人妻无码中文字幕爆 | 亚洲国产精品久久久久久 | 国产口爆吞精在线视频 | 牲欲强的熟妇农村老妇女 | 亚洲 高清 成人 动漫 | 久久人人爽人人人人片 | 九九综合va免费看 | 无码国产色欲xxxxx视频 | 国产高潮视频在线观看 | 四虎影视成人永久免费观看视频 | 免费国产成人高清在线观看网站 | 天天躁夜夜躁狠狠是什么心态 | 夜精品a片一区二区三区无码白浆 | 国产深夜福利视频在线 | 久激情内射婷内射蜜桃人妖 | 精品国产国产综合精品 | 好男人www社区 | 精品无码一区二区三区的天堂 | 人妻无码αv中文字幕久久琪琪布 | 欧美精品免费观看二区 | 国产亚洲精品久久久久久大师 | 丰满诱人的人妻3 | 亚洲无人区午夜福利码高清完整版 | 久久www免费人成人片 | 乱人伦人妻中文字幕无码 | 久久久无码中文字幕久... | 国内精品人妻无码久久久影院 | 国产在线无码精品电影网 | 麻豆精产国品 | 动漫av一区二区在线观看 | av香港经典三级级 在线 | 三级4级全黄60分钟 | 国产成人精品久久亚洲高清不卡 | 亚洲精品无码国产 | 亚洲精品无码国产 | 成人性做爰aaa片免费看 | 奇米影视7777久久精品人人爽 | 日产精品高潮呻吟av久久 | 亚洲成av人片在线观看无码不卡 | 国产两女互慰高潮视频在线观看 | 亚洲精品国产品国语在线观看 | 欧美日韩精品 | 丰满人妻被黑人猛烈进入 | 美女扒开屁股让男人桶 | 日韩人妻系列无码专区 | 领导边摸边吃奶边做爽在线观看 | 成人亚洲精品久久久久 | 人妻无码久久精品人妻 | 国产免费久久精品国产传媒 | 久久亚洲日韩精品一区二区三区 | 亚洲精品一区二区三区在线观看 | 色综合天天综合狠狠爱 | 国产精品久久久久久久9999 | 久久亚洲精品成人无码 | 亚洲熟悉妇女xxx妇女av | 少妇高潮喷潮久久久影院 | 亚洲 日韩 欧美 成人 在线观看 | 久久久中文字幕日本无吗 | 国产女主播喷水视频在线观看 | 内射老妇bbwx0c0ck | 亚洲精品久久久久avwww潮水 | 成人亚洲精品久久久久软件 | 鲁一鲁av2019在线 | 少妇久久久久久人妻无码 | 亚洲s码欧洲m码国产av | 中文字幕日产无线码一区 | 亚洲大尺度无码无码专区 | 亚洲の无码国产の无码影院 | 18精品久久久无码午夜福利 | 欧美国产日韩亚洲中文 | 日本熟妇人妻xxxxx人hd | 好爽又高潮了毛片免费下载 | 亚洲va中文字幕无码久久不卡 | 亚洲va中文字幕无码久久不卡 | 激情国产av做激情国产爱 | 日本一区二区更新不卡 | 国产人妻久久精品二区三区老狼 | 亚洲日本在线电影 | 色情久久久av熟女人妻网站 | 久久99精品国产.久久久久 | 99久久久无码国产aaa精品 | 亚洲国产精品久久久久久 | 天下第一社区视频www日本 | 精品国产国产综合精品 | 国产成人人人97超碰超爽8 | 亚洲成av人片天堂网无码】 | 粉嫩少妇内射浓精videos | 国产激情无码一区二区 | 在线观看国产午夜福利片 | 亚洲中文字幕乱码av波多ji | 在线观看国产午夜福利片 | 国产精品国产三级国产专播 | 精品国产福利一区二区 | 久久久成人毛片无码 | 午夜丰满少妇性开放视频 | 无码人妻久久一区二区三区不卡 | 青青青手机频在线观看 | 久久国产精品萌白酱免费 | 扒开双腿疯狂进出爽爽爽视频 | 东京一本一道一二三区 | 大肉大捧一进一出好爽视频 | 人妻少妇精品视频专区 | 丁香啪啪综合成人亚洲 | 沈阳熟女露脸对白视频 | 国产香蕉97碰碰久久人人 | 欧美xxxx黑人又粗又长 | 国产精品高潮呻吟av久久 | 欧美日本日韩 | 牛和人交xxxx欧美 | 久久亚洲中文字幕无码 | 国产av一区二区三区最新精品 | 在线播放免费人成毛片乱码 | 免费播放一区二区三区 | 无码福利日韩神码福利片 | 东京热无码av男人的天堂 | 久久精品国产一区二区三区肥胖 | 成人欧美一区二区三区黑人免费 | 国产口爆吞精在线视频 | 无人区乱码一区二区三区 | 色综合视频一区二区三区 | 亚洲伊人久久精品影院 | 欧美国产日产一区二区 | 无码午夜成人1000部免费视频 | 国产亚洲精品久久久久久大师 | 精品成在人线av无码免费看 | 日欧一片内射va在线影院 | 欧美老妇交乱视频在线观看 | 荡女精品导航 | 荡女精品导航 | 欧美人与动性行为视频 | 九九综合va免费看 | 亚洲色欲色欲天天天www | 国内丰满熟女出轨videos | 麻豆av传媒蜜桃天美传媒 | 啦啦啦www在线观看免费视频 | 久久午夜无码鲁丝片秋霞 | 婷婷丁香五月天综合东京热 | 中文字幕人妻无码一区二区三区 | 亚洲精品成人av在线 | 精品无码成人片一区二区98 | 精品无码av一区二区三区 | 无遮挡国产高潮视频免费观看 | 国产69精品久久久久app下载 | 亚洲高清偷拍一区二区三区 | 国产精品无码永久免费888 | 女人和拘做爰正片视频 | 免费无码肉片在线观看 | 国产精品国产三级国产专播 | 在线看片无码永久免费视频 | 波多野42部无码喷潮在线 | 日日干夜夜干 | 色欲久久久天天天综合网精品 | 成人精品天堂一区二区三区 | 永久免费观看国产裸体美女 | 中文久久乱码一区二区 | 男人扒开女人内裤强吻桶进去 | 国产suv精品一区二区五 | 欧美成人高清在线播放 | 久久久精品人妻久久影视 | 国产做国产爱免费视频 | 国产无遮挡又黄又爽免费视频 | 真人与拘做受免费视频一 | 131美女爱做视频 | 夜夜高潮次次欢爽av女 | 少妇被粗大的猛进出69影院 | 精品aⅴ一区二区三区 | 乌克兰少妇性做爰 | 国产热a欧美热a在线视频 | 国产精品二区一区二区aⅴ污介绍 | 精品无码一区二区三区爱欲 | 亚洲精品鲁一鲁一区二区三区 | 日日摸天天摸爽爽狠狠97 | 国产一区二区三区四区五区加勒比 | 大地资源网第二页免费观看 | 欧美怡红院免费全部视频 | 又大又紧又粉嫩18p少妇 | 亚洲国产精品美女久久久久 | 色老头在线一区二区三区 | 国产亚洲精品久久久久久大师 | 大色综合色综合网站 | 久久国产精品萌白酱免费 | 99久久人妻精品免费一区 | 狠狠色噜噜狠狠狠7777奇米 | 无码乱肉视频免费大全合集 | 亚洲精品成人福利网站 | 亚洲精品中文字幕久久久久 | 亚洲精品国产精品乱码不卡 | 无码av岛国片在线播放 | 丝袜足控一区二区三区 | 激情国产av做激情国产爱 | 又粗又大又硬毛片免费看 | 国精品人妻无码一区二区三区蜜柚 | 精品偷拍一区二区三区在线看 | 亚洲色大成网站www | 奇米影视7777久久精品人人爽 | 精品乱码久久久久久久 | 国产精品久久久久久久9999 | 国产精品无码久久av | 欧美老妇交乱视频在线观看 | 樱花草在线社区www | 国产亚洲精品久久久久久国模美 | 成人精品一区二区三区中文字幕 | 国产乱人偷精品人妻a片 | 又粗又大又硬毛片免费看 | 成熟女人特级毛片www免费 | 俄罗斯老熟妇色xxxx | 欧美老妇交乱视频在线观看 | 日韩 欧美 动漫 国产 制服 | 日韩精品无码一区二区中文字幕 | 精品国精品国产自在久国产87 | 国产成人一区二区三区别 | 日本精品少妇一区二区三区 | 久久视频在线观看精品 | 国产精品亚洲一区二区三区喷水 | 日韩精品无码一区二区中文字幕 | 无码国产激情在线观看 | 国产福利视频一区二区 | aⅴ在线视频男人的天堂 | 日本精品人妻无码免费大全 | 精品亚洲韩国一区二区三区 | 国产一区二区三区影院 | 天堂久久天堂av色综合 | aⅴ亚洲 日韩 色 图网站 播放 | 精品一区二区三区波多野结衣 | 少妇激情av一区二区 | 国产精品成人av在线观看 | 国产午夜福利100集发布 | 曰本女人与公拘交酡免费视频 | 一本大道久久东京热无码av | 亚洲а∨天堂久久精品2021 | 欧美自拍另类欧美综合图片区 | 久久久久久久久888 | 久久综合网欧美色妞网 | 丰腴饱满的极品熟妇 | 国产亚洲精品久久久ai换 | 国产特级毛片aaaaaa高潮流水 | 亚洲成av人片天堂网无码】 | 精品无码一区二区三区爱欲 | 国产精品无码一区二区三区不卡 | 亚洲乱码中文字幕在线 | 日韩精品无码一区二区中文字幕 | 国产亚洲精品久久久ai换 | 18禁黄网站男男禁片免费观看 | 熟妇人妻无乱码中文字幕 | 久久国内精品自在自线 | 2019午夜福利不卡片在线 | 欧美日本免费一区二区三区 | 又大又紧又粉嫩18p少妇 | 久久久久久久人妻无码中文字幕爆 | 日韩欧美中文字幕在线三区 | 亚洲欧美日韩综合久久久 | 黑人大群体交免费视频 | 国产又粗又硬又大爽黄老大爷视 | 亚洲精品国偷拍自产在线观看蜜桃 | 成人亚洲精品久久久久软件 | 中文精品久久久久人妻不卡 | 女高中生第一次破苞av | 日韩精品无码一区二区中文字幕 | 亚洲国产精品无码一区二区三区 | 久久亚洲日韩精品一区二区三区 | 国产亚洲精品久久久久久国模美 | 天堂久久天堂av色综合 | 国产精品无码一区二区桃花视频 | 成人aaa片一区国产精品 | 国产午夜精品一区二区三区嫩草 | 日本熟妇乱子伦xxxx | 亚洲人亚洲人成电影网站色 | 日韩欧美群交p片內射中文 | 欧美肥老太牲交大战 | 国产电影无码午夜在线播放 | 在线播放免费人成毛片乱码 | 国产人妻久久精品二区三区老狼 | 久久久久久av无码免费看大片 | 久久人妻内射无码一区三区 | 国产av人人夜夜澡人人爽麻豆 | 激情亚洲一区国产精品 | 国产尤物精品视频 | 男女猛烈xx00免费视频试看 | 人妻插b视频一区二区三区 | 18精品久久久无码午夜福利 | www国产亚洲精品久久网站 | 老司机亚洲精品影院无码 | 亚洲精品鲁一鲁一区二区三区 | 东京热一精品无码av | 亚洲小说图区综合在线 | 又湿又紧又大又爽a视频国产 | 美女黄网站人色视频免费国产 | 成人毛片一区二区 | 乱码午夜-极国产极内射 | 狠狠色丁香久久婷婷综合五月 | 久久国产劲爆∧v内射 | 丰满肥臀大屁股熟妇激情视频 | 国产精品美女久久久 | 国产又粗又硬又大爽黄老大爷视 | 帮老师解开蕾丝奶罩吸乳网站 | 曰本女人与公拘交酡免费视频 | 嫩b人妻精品一区二区三区 | 国产精品久久久久无码av色戒 | 黑人巨大精品欧美一区二区 | 人人爽人人澡人人人妻 | 狂野欧美激情性xxxx | 中文字幕亚洲情99在线 | 国产欧美熟妇另类久久久 | 妺妺窝人体色www在线小说 | 成人片黄网站色大片免费观看 | 亚洲国精产品一二二线 | 国产午夜亚洲精品不卡 | 亚洲国产高清在线观看视频 | 欧洲熟妇精品视频 | 亚洲色偷偷男人的天堂 | 国产黑色丝袜在线播放 | 精品人妻人人做人人爽 | 中文字幕无码免费久久99 | 欧美国产日韩久久mv | 在线а√天堂中文官网 | 亚洲成熟女人毛毛耸耸多 | 精品午夜福利在线观看 | yw尤物av无码国产在线观看 | 天天av天天av天天透 | 欧美阿v高清资源不卡在线播放 | 无码乱肉视频免费大全合集 | 亚洲国产精品久久人人爱 | 人妻人人添人妻人人爱 | 国产农村妇女高潮大叫 | 妺妺窝人体色www婷婷 | 国产国产精品人在线视 | 国产偷国产偷精品高清尤物 | 欧美国产亚洲日韩在线二区 | 欧美精品国产综合久久 | 亚拍精品一区二区三区探花 | 偷窥村妇洗澡毛毛多 | 亚洲乱码日产精品bd | 秋霞成人午夜鲁丝一区二区三区 | 99精品久久毛片a片 | 成人精品天堂一区二区三区 | 俺去俺来也在线www色官网 | 亚洲の无码国产の无码影院 | 奇米影视7777久久精品 | 欧美丰满熟妇xxxx性ppx人交 | 国产精品久久国产三级国 | 成年女人永久免费看片 | 男女超爽视频免费播放 | 亚洲日韩av一区二区三区中文 | 国产又粗又硬又大爽黄老大爷视 | 一区二区三区乱码在线 | 欧洲 | 国内丰满熟女出轨videos | 人人澡人人妻人人爽人人蜜桃 | 国内少妇偷人精品视频 | 亚洲精品久久久久中文第一幕 | 精品久久久中文字幕人妻 | 色 综合 欧美 亚洲 国产 | 无码人妻少妇伦在线电影 | 亚洲乱码日产精品bd | 中文字幕av日韩精品一区二区 | 亚洲一区二区三区播放 | 亚洲成色在线综合网站 | 久久成人a毛片免费观看网站 | 欧美人与禽zoz0性伦交 | 欧美 亚洲 国产 另类 | 亚洲精品国产第一综合99久久 | 亚洲第一网站男人都懂 | 无码精品人妻一区二区三区av | 久久精品一区二区三区四区 | 亚洲热妇无码av在线播放 | 亚洲а∨天堂久久精品2021 | 扒开双腿疯狂进出爽爽爽视频 | 高清不卡一区二区三区 | 成人毛片一区二区 | 香蕉久久久久久av成人 | 精品国产麻豆免费人成网站 | 久久zyz资源站无码中文动漫 | 亚洲精品久久久久久久久久久 | 婷婷丁香五月天综合东京热 | 日本乱偷人妻中文字幕 | 丁香花在线影院观看在线播放 | 日本熟妇乱子伦xxxx | 国产亚av手机在线观看 | 99久久精品午夜一区二区 | 亚洲综合另类小说色区 | 亚洲一区二区三区 | 女人高潮内射99精品 | 波多野结衣av一区二区全免费观看 | 永久免费观看国产裸体美女 | 久久午夜无码鲁丝片 | 亚洲无人区一区二区三区 | 精品无码一区二区三区的天堂 | 久久久久久久人妻无码中文字幕爆 | 亚洲中文字幕乱码av波多ji | 亚洲日韩中文字幕在线播放 | 人人妻人人澡人人爽欧美一区 | 波多野结衣一区二区三区av免费 | 国产精品香蕉在线观看 | 中文字幕人成乱码熟女app | 日本在线高清不卡免费播放 | 麻豆人妻少妇精品无码专区 | 少妇高潮一区二区三区99 | 免费观看激色视频网站 | 女人被爽到呻吟gif动态图视看 | 国产成人综合在线女婷五月99播放 | 大色综合色综合网站 | 亚洲区欧美区综合区自拍区 | 又湿又紧又大又爽a视频国产 | av人摸人人人澡人人超碰下载 | 国产成人久久精品流白浆 | 国产亚洲精品久久久久久大师 | 夜夜夜高潮夜夜爽夜夜爰爰 | 一个人看的视频www在线 | 精品无人区无码乱码毛片国产 | 亚洲日韩一区二区 | 国产美女极度色诱视频www | 欧美精品无码一区二区三区 | 国产精品久久久午夜夜伦鲁鲁 | 久久综合久久自在自线精品自 | 久久天天躁夜夜躁狠狠 | 丰满人妻被黑人猛烈进入 | 成人免费无码大片a毛片 | www国产精品内射老师 | 国产又爽又黄又刺激的视频 | av在线亚洲欧洲日产一区二区 | 欧美性黑人极品hd | 奇米影视888欧美在线观看 | 国产精品美女久久久网av | 日本护士xxxxhd少妇 | 日本又色又爽又黄的a片18禁 | 性啪啪chinese东北女人 | 午夜福利一区二区三区在线观看 | 国产卡一卡二卡三 | 无套内谢的新婚少妇国语播放 | 国产成人一区二区三区别 | 国产精品资源一区二区 | 色老头在线一区二区三区 | 性开放的女人aaa片 | 无码纯肉视频在线观看 | 亚洲国产精品一区二区美利坚 | 久久久久av无码免费网 | 亚洲毛片av日韩av无码 | 亚洲国产精品无码久久久久高潮 | 一区二区三区高清视频一 | 日本精品久久久久中文字幕 | 福利一区二区三区视频在线观看 | 国内精品九九久久久精品 | 人人妻人人澡人人爽欧美精品 | 精品国产av色一区二区深夜久久 | 麻豆蜜桃av蜜臀av色欲av | 亚洲欧美精品aaaaaa片 | 丰满人妻翻云覆雨呻吟视频 | 美女张开腿让人桶 | 荫蒂被男人添的好舒服爽免费视频 | 欧美人与禽猛交狂配 | 亚洲精品午夜国产va久久成人 | 成人女人看片免费视频放人 | 一本久道久久综合狠狠爱 | 18禁止看的免费污网站 | 久久综合激激的五月天 | 中文字幕无码热在线视频 | 欧美激情综合亚洲一二区 | 国产精品嫩草久久久久 | 国产香蕉尹人视频在线 | 日本饥渴人妻欲求不满 | 偷窥日本少妇撒尿chinese | 免费人成在线观看网站 | 精品人妻av区 | 无码人中文字幕 | 无码国内精品人妻少妇 | 又大又硬又黄的免费视频 | 国产成人无码a区在线观看视频app | 亚洲人成影院在线观看 | 久久久久亚洲精品男人的天堂 | 国产成人久久精品流白浆 | 色 综合 欧美 亚洲 国产 | 四虎永久在线精品免费网址 | 学生妹亚洲一区二区 | 国产 浪潮av性色四虎 | 欧美日韩视频无码一区二区三 | 日本va欧美va欧美va精品 | 亚洲娇小与黑人巨大交 | 亚洲日韩一区二区三区 | 一个人看的视频www在线 | 国产一区二区三区四区五区加勒比 | 在线视频网站www色 | 天天综合网天天综合色 | 免费国产成人高清在线观看网站 | 国产精品美女久久久 | 亚洲一区二区三区在线观看网站 | 999久久久国产精品消防器材 | 2020最新国产自产精品 | 2019午夜福利不卡片在线 | 精品水蜜桃久久久久久久 | 伊在人天堂亚洲香蕉精品区 | 无码人妻av免费一区二区三区 | 国产精华av午夜在线观看 | 中文字幕 亚洲精品 第1页 | 又大又硬又爽免费视频 | 亚洲欧洲中文日韩av乱码 | 装睡被陌生人摸出水好爽 | 人人妻人人澡人人爽人人精品 | 精品久久久久香蕉网 | 美女黄网站人色视频免费国产 | 国产成人无码a区在线观看视频app | 久久99精品久久久久久动态图 | 亚洲一区二区三区播放 | 亚洲小说图区综合在线 | 鲁一鲁av2019在线 | 午夜精品久久久久久久久 | 日日夜夜撸啊撸 | 狂野欧美性猛xxxx乱大交 | 在线亚洲高清揄拍自拍一品区 | 无码国产乱人伦偷精品视频 | 国产香蕉尹人综合在线观看 | 久久 国产 尿 小便 嘘嘘 | 亚洲欧美国产精品专区久久 | 久久99精品国产麻豆 | 国产午夜无码视频在线观看 | 无套内谢的新婚少妇国语播放 | 色五月五月丁香亚洲综合网 | 亚洲精品美女久久久久久久 | 欧美日韩一区二区综合 | 成人免费视频视频在线观看 免费 | 欧美老妇与禽交 | 国产亚洲精品久久久久久久 | 狠狠噜狠狠狠狠丁香五月 | 中文字幕乱妇无码av在线 | 免费无码的av片在线观看 | 狠狠色欧美亚洲狠狠色www | 欧美自拍另类欧美综合图片区 | 欧美刺激性大交 | 国产精品久久久久久久影院 | 亚洲欧洲无卡二区视頻 | 大肉大捧一进一出好爽视频 | 性色欲情网站iwww九文堂 | 久9re热视频这里只有精品 | 国内精品人妻无码久久久影院蜜桃 | 亚洲精品国产第一综合99久久 | 久久人人爽人人爽人人片av高清 | 人人妻人人澡人人爽欧美一区九九 | 亚洲aⅴ无码成人网站国产app | 免费观看又污又黄的网站 | 中文字幕无码日韩欧毛 | √天堂资源地址中文在线 | 人人妻人人藻人人爽欧美一区 | 丰满诱人的人妻3 | 无码人妻久久一区二区三区不卡 | 又大又黄又粗又爽的免费视频 | 久久伊人色av天堂九九小黄鸭 | 人人澡人人妻人人爽人人蜜桃 | 少妇厨房愉情理9仑片视频 | 亚洲精品鲁一鲁一区二区三区 | 亚洲日韩精品欧美一区二区 | 日韩视频 中文字幕 视频一区 | 午夜精品久久久内射近拍高清 | 亚欧洲精品在线视频免费观看 | 丰满人妻一区二区三区免费视频 | 国产人妻精品一区二区三区不卡 | 国产超碰人人爽人人做人人添 | 中文字幕乱码中文乱码51精品 | 亚洲国产精品无码一区二区三区 | 亚洲欧洲日本无在线码 | 国产女主播喷水视频在线观看 | 色综合久久88色综合天天 | 西西人体www44rt大胆高清 | 性生交片免费无码看人 | 天堂а√在线地址中文在线 | 无码国模国产在线观看 | 7777奇米四色成人眼影 | 在线天堂新版最新版在线8 | 日本精品高清一区二区 | 国产在热线精品视频 | 欧美野外疯狂做受xxxx高潮 | ass日本丰满熟妇pics | 成在人线av无码免费 | 国精品人妻无码一区二区三区蜜柚 | 狠狠cao日日穞夜夜穞av | 国产精品美女久久久久av爽李琼 | 大肉大捧一进一出视频出来呀 | 无码av岛国片在线播放 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 最近免费中文字幕中文高清百度 | 狠狠色噜噜狠狠狠7777奇米 | 中文字幕无码日韩专区 | 高清无码午夜福利视频 | 久青草影院在线观看国产 | 亚洲色在线无码国产精品不卡 | 欧美日韩人成综合在线播放 | 久久97精品久久久久久久不卡 | 天天综合网天天综合色 | 欧美亚洲日韩国产人成在线播放 | 精品久久久久久亚洲精品 | 国产日产欧产精品精品app | 国产精品久久久久久亚洲毛片 | 国产人妻大战黑人第1集 | 色综合久久久久综合一本到桃花网 | 国产肉丝袜在线观看 | 亚洲人成影院在线无码按摩店 | 玩弄人妻少妇500系列视频 | 国产精品18久久久久久麻辣 | 国产精品人人妻人人爽 | 婷婷五月综合缴情在线视频 | 天堂无码人妻精品一区二区三区 | 成人亚洲精品久久久久软件 | 人妻互换免费中文字幕 | 麻豆果冻传媒2021精品传媒一区下载 | 欧美阿v高清资源不卡在线播放 | 国产亚洲欧美日韩亚洲中文色 | 国产精品免费大片 | 精品国偷自产在线视频 | 国产精品无码一区二区桃花视频 | 波多野结衣高清一区二区三区 | 中文字幕无码av波多野吉衣 | 国产人妖乱国产精品人妖 | 欧美肥老太牲交大战 | 人人澡人人妻人人爽人人蜜桃 | 久久zyz资源站无码中文动漫 | 性欧美大战久久久久久久 | 亚洲色欲色欲天天天www | 中文字幕久久久久人妻 | 宝宝好涨水快流出来免费视频 | 无码av岛国片在线播放 | 国内少妇偷人精品视频免费 | 日日碰狠狠躁久久躁蜜桃 | 99久久无码一区人妻 | 天天av天天av天天透 | 熟妇人妻激情偷爽文 | 日韩av激情在线观看 | 久久久久免费看成人影片 | 99riav国产精品视频 | 国产成人无码午夜视频在线观看 | 老头边吃奶边弄进去呻吟 | 亚洲精品中文字幕久久久久 | 亚洲一区二区三区国产精华液 | 亚洲成在人网站无码天堂 | 欧美日韩一区二区免费视频 | 国内精品一区二区三区不卡 | 亚洲色偷偷偷综合网 | 久久久www成人免费毛片 | 精品国产一区二区三区四区在线看 | 国产成人无码午夜视频在线观看 | 欧美性黑人极品hd | 欧美成人家庭影院 | 中文字幕 亚洲精品 第1页 | 久久久中文久久久无码 | 午夜性刺激在线视频免费 | 麻豆蜜桃av蜜臀av色欲av | 久久久久久a亚洲欧洲av冫 | 亚洲熟妇自偷自拍另类 | 日本熟妇大屁股人妻 | 亚洲一区二区三区偷拍女厕 | 亚洲人成人无码网www国产 | 亚洲中文字幕乱码av波多ji | 日本精品人妻无码免费大全 | 在教室伦流澡到高潮hnp视频 | 亚洲色欲色欲天天天www | 无码播放一区二区三区 | 日韩欧美群交p片內射中文 | 天天躁日日躁狠狠躁免费麻豆 | 丁香啪啪综合成人亚洲 | 巨爆乳无码视频在线观看 | 欧美人妻一区二区三区 | 国产高清不卡无码视频 | 无码播放一区二区三区 | 欧美日韩综合一区二区三区 | 久久久久久久久蜜桃 | 伊人色综合久久天天小片 | 天天爽夜夜爽夜夜爽 | 国产亚洲精品久久久久久国模美 | 国产乱人伦av在线无码 | 欧美freesex黑人又粗又大 | 亚洲成色在线综合网站 | 国产绳艺sm调教室论坛 | 国产精品多人p群无码 | 久久国内精品自在自线 | 国产女主播喷水视频在线观看 | 国产精品毛片一区二区 | 99久久99久久免费精品蜜桃 | 亚洲熟妇色xxxxx欧美老妇 | 婷婷丁香六月激情综合啪 | 熟女俱乐部五十路六十路av | 大地资源中文第3页 | 久久午夜无码鲁丝片午夜精品 | 大乳丰满人妻中文字幕日本 | 夜夜躁日日躁狠狠久久av | 国产三级精品三级男人的天堂 | 成人欧美一区二区三区黑人免费 | 成人性做爰aaa片免费看 | 久久综合久久自在自线精品自 | 国产凸凹视频一区二区 | 俺去俺来也在线www色官网 | 丰满少妇熟乱xxxxx视频 | 国内丰满熟女出轨videos | 天堂久久天堂av色综合 | 亚洲精品欧美二区三区中文字幕 | 久久99精品久久久久久动态图 | 久久久久久久久888 | 色一情一乱一伦一视频免费看 | 国产精品久久久久久亚洲毛片 | 久久久中文字幕日本无吗 | 国产手机在线αⅴ片无码观看 | 97久久超碰中文字幕 | 久久久久久av无码免费看大片 | 人人妻人人澡人人爽欧美一区 | 国产午夜无码视频在线观看 | 欧美亚洲日韩国产人成在线播放 | 蜜桃视频韩日免费播放 | 中国大陆精品视频xxxx | 人人澡人人透人人爽 | 伊人久久大香线蕉av一区二区 | 国产乱人无码伦av在线a | 欧美熟妇另类久久久久久不卡 | 老熟妇仑乱视频一区二区 | 暴力强奷在线播放无码 | 亚洲一区二区三区国产精华液 | 精品乱子伦一区二区三区 | 爱做久久久久久 | 少妇一晚三次一区二区三区 | 无套内射视频囯产 | 狠狠色丁香久久婷婷综合五月 | 无码成人精品区在线观看 | 亚洲午夜福利在线观看 | 玩弄中年熟妇正在播放 | 国产精品99久久精品爆乳 | 宝宝好涨水快流出来免费视频 | 高清不卡一区二区三区 | 久久精品99久久香蕉国产色戒 | 最新国产乱人伦偷精品免费网站 | 男人的天堂2018无码 | 国产精品沙发午睡系列 | 高潮毛片无遮挡高清免费视频 | 国产精品自产拍在线观看 | 国产午夜无码视频在线观看 | 亚洲精品久久久久久久久久久 | 午夜精品久久久久久久久 | 久久国产自偷自偷免费一区调 | 免费人成网站视频在线观看 | 老司机亚洲精品影院无码 | 夜先锋av资源网站 | 国产成人无码一二三区视频 | 国产97人人超碰caoprom | 亚洲成av人片天堂网无码】 | 俄罗斯老熟妇色xxxx | 国产亚洲视频中文字幕97精品 | 国产人妻精品一区二区三区不卡 | 玩弄人妻少妇500系列视频 | 性色欲网站人妻丰满中文久久不卡 | 国产成人无码午夜视频在线观看 | 国产小呦泬泬99精品 | 少妇人妻av毛片在线看 | 久久99精品久久久久久动态图 | 97夜夜澡人人爽人人喊中国片 | 久久99精品久久久久久动态图 | 亲嘴扒胸摸屁股激烈网站 | 日日橹狠狠爱欧美视频 | 在线视频网站www色 | 丰满人妻翻云覆雨呻吟视频 | 国产精品a成v人在线播放 | 欧美黑人巨大xxxxx | 99国产欧美久久久精品 | 国产一区二区三区日韩精品 | 亚洲欧美综合区丁香五月小说 | 久久精品国产精品国产精品污 | а√天堂www在线天堂小说 | 日本一卡2卡3卡四卡精品网站 | 西西人体www44rt大胆高清 | 国产精品欧美成人 | 国产小呦泬泬99精品 | 亚洲国产成人av在线观看 | 中文精品无码中文字幕无码专区 | 高清国产亚洲精品自在久久 | 色偷偷人人澡人人爽人人模 | 日韩精品一区二区av在线 | 鲁鲁鲁爽爽爽在线视频观看 | 熟妇女人妻丰满少妇中文字幕 | 国产午夜手机精彩视频 | 亚洲性无码av中文字幕 | 又黄又爽又色的视频 | 中文字幕无码av激情不卡 | 日本xxxx色视频在线观看免费 | 色欲av亚洲一区无码少妇 | 一个人免费观看的www视频 | 午夜精品久久久内射近拍高清 | 夜夜影院未满十八勿进 | 国产精品久久国产三级国 | 国产偷国产偷精品高清尤物 | 久久精品中文字幕大胸 | 女人被男人爽到呻吟的视频 | 亚洲爆乳精品无码一区二区三区 | 亚洲色偷偷男人的天堂 | 精品水蜜桃久久久久久久 | 啦啦啦www在线观看免费视频 | 特黄特色大片免费播放器图片 | 18无码粉嫩小泬无套在线观看 | 中文字幕日产无线码一区 | 高中生自慰www网站 | 亚洲精品一区二区三区在线观看 | 未满小14洗澡无码视频网站 | 天堂亚洲免费视频 | 图片区 小说区 区 亚洲五月 | 国产成人精品一区二区在线小狼 | 日本精品人妻无码77777 天堂一区人妻无码 | 97精品国产97久久久久久免费 | 国精品人妻无码一区二区三区蜜柚 | 丰满少妇人妻久久久久久 | 精品国精品国产自在久国产87 | 熟妇人妻中文av无码 | 午夜无码人妻av大片色欲 | 亚洲色偷偷偷综合网 | 牲交欧美兽交欧美 | 国产成人无码av在线影院 | 欧美真人作爱免费视频 | 欧美日韩在线亚洲综合国产人 | 久久久亚洲欧洲日产国码αv | 成人精品视频一区二区 | 精品国偷自产在线 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 乱中年女人伦av三区 | 亚洲七七久久桃花影院 | 午夜男女很黄的视频 | 97精品人妻一区二区三区香蕉 | 亚洲国产日韩a在线播放 | 久久www免费人成人片 | 成人aaa片一区国产精品 | 国产午夜视频在线观看 | 天下第一社区视频www日本 | 色一情一乱一伦一区二区三欧美 | 99国产欧美久久久精品 | 伊人久久大香线蕉午夜 | 97色伦图片97综合影院 | 最近的中文字幕在线看视频 | 美女张开腿让人桶 | 日日碰狠狠躁久久躁蜜桃 | 四虎永久在线精品免费网址 | 亚洲熟悉妇女xxx妇女av | 小泽玛莉亚一区二区视频在线 | 高清不卡一区二区三区 | 四虎影视成人永久免费观看视频 | 亚洲国产精品美女久久久久 | 成人试看120秒体验区 | 久久99精品国产麻豆蜜芽 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 真人与拘做受免费视频 | 欧美freesex黑人又粗又大 | 久久久成人毛片无码 | 娇妻被黑人粗大高潮白浆 | 激情综合激情五月俺也去 | 亚洲中文字幕无码中字 | 美女极度色诱视频国产 | 理论片87福利理论电影 | 精品久久8x国产免费观看 | 久久国产精品精品国产色婷婷 | 中文字幕人妻无码一区二区三区 | 精品国产一区二区三区四区 | 亚洲综合另类小说色区 | 国产香蕉97碰碰久久人人 | 久久久久免费精品国产 | 老司机亚洲精品影院无码 | 300部国产真实乱 | 又粗又大又硬又长又爽 | 乱人伦人妻中文字幕无码久久网 | 久久久久国色av免费观看性色 | 国产人妻精品一区二区三区 | 99久久精品国产一区二区蜜芽 | 牲交欧美兽交欧美 | 久久精品中文闷骚内射 | 久久精品女人的天堂av | 无码国产乱人伦偷精品视频 | 久久综合给合久久狠狠狠97色 | 国产艳妇av在线观看果冻传媒 | 九九久久精品国产免费看小说 | 亚洲呦女专区 | 国产精品对白交换视频 | a在线亚洲男人的天堂 | 女人高潮内射99精品 | 精品无码av一区二区三区 | 亚洲精品久久久久久一区二区 | 自拍偷自拍亚洲精品被多人伦好爽 | 波多野结衣一区二区三区av免费 | 久久久精品456亚洲影院 | 日本精品人妻无码77777 天堂一区人妻无码 | a国产一区二区免费入口 | 清纯唯美经典一区二区 | 国产精品久久久久久久9999 | 日本肉体xxxx裸交 | av无码不卡在线观看免费 | 久久国产精品偷任你爽任你 | 成人一在线视频日韩国产 | 国产三级精品三级男人的天堂 | 精品久久久无码中文字幕 | 人人妻人人藻人人爽欧美一区 | 一本无码人妻在中文字幕免费 | 狠狠色欧美亚洲狠狠色www | 西西人体www44rt大胆高清 | 中文字幕日产无线码一区 | 国产在线无码精品电影网 | 搡女人真爽免费视频大全 | 性色欲网站人妻丰满中文久久不卡 | 欧美日韩在线亚洲综合国产人 | 国产综合久久久久鬼色 | 国产亚洲精品久久久久久国模美 | 精品久久综合1区2区3区激情 | 亚洲综合无码久久精品综合 | 乱码午夜-极国产极内射 | 国产精品爱久久久久久久 | 欧美成人免费全部网站 | 成人试看120秒体验区 | 国产av一区二区三区最新精品 | 亚洲成熟女人毛毛耸耸多 | 国产国语老龄妇女a片 | 97人妻精品一区二区三区 | 乱人伦中文视频在线观看 | 丰满人妻精品国产99aⅴ | 在线精品国产一区二区三区 | 日本饥渴人妻欲求不满 | 骚片av蜜桃精品一区 | 色婷婷综合中文久久一本 | 亚洲欧洲日本无在线码 | 精品一区二区三区波多野结衣 | 女人色极品影院 | 老头边吃奶边弄进去呻吟 | 丝袜 中出 制服 人妻 美腿 | 中文字幕日产无线码一区 | 亚洲熟妇色xxxxx欧美老妇y | 国产亚洲精品久久久久久久 | 在线a亚洲视频播放在线观看 | 丰满人妻被黑人猛烈进入 | 人人妻人人澡人人爽精品欧美 | 久久精品人妻少妇一区二区三区 | 日韩视频 中文字幕 视频一区 | 久在线观看福利视频 | 国模大胆一区二区三区 | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲精品午夜无码电影网 | 日本熟妇浓毛 | 76少妇精品导航 | 精品无人国产偷自产在线 | 国产人妻久久精品二区三区老狼 | 国产国产精品人在线视 | 午夜成人1000部免费视频 | 巨爆乳无码视频在线观看 | 欧美国产日韩亚洲中文 | 露脸叫床粗话东北少妇 | 日韩欧美中文字幕在线三区 | 欧美变态另类xxxx | 国产成人综合色在线观看网站 | 人妻体内射精一区二区三四 | 欧美阿v高清资源不卡在线播放 | 最新国产麻豆aⅴ精品无码 | 欧美人与禽zoz0性伦交 | 精品久久综合1区2区3区激情 | 亚洲伊人久久精品影院 |