2007年8月10日
自動(dòng)生成的工程文件配置的PreprocessorDefinitions 是 WIN32;_DEBUG;_WINDOWS
需要改成 PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;UNICODE;_WIN32_WINNT=0x0501"
有的項(xiàng)目編譯不了是因?yàn)?CharacterSet 的問題
六年前,我剛熱戀“面向?qū)ο?#8221;(Object-Oriented)時(shí),一口氣記住了近十個(gè)定義。六年后,我從幾十萬(wàn)行程序中滾爬出來(lái)準(zhǔn)備寫點(diǎn)心得體會(huì)時(shí),卻無(wú)法解釋什么是“面向?qū)ο?#8221;,就象說(shuō)不清楚什么是數(shù)學(xué)那樣。軟件工程中的時(shí)髦術(shù)語(yǔ)“面向?qū)ο蠓治?#8221;和“面向?qū)ο笤O(shè)計(jì)”,通常是針對(duì)“需求分析”和“系統(tǒng)設(shè)計(jì)”環(huán)節(jié)的。“面向?qū)ο?#8221;有幾大學(xué)派,就象如來(lái)佛、上帝和真主用各自的方式定義了這個(gè)世界,并留下一堆經(jīng)書來(lái)解釋這個(gè)世界。
有些學(xué)者建議這樣找“對(duì)象”:分析一個(gè)句子的語(yǔ)法,找出名詞和動(dòng)詞,名詞就是對(duì)象,動(dòng)詞則是對(duì)象的方法(即函數(shù))。
當(dāng)年國(guó)民黨的文人為了對(duì)抗毛澤東的《沁園春·雪》,特意請(qǐng)清朝遺老們寫了一些對(duì)仗工整的詩(shī),請(qǐng)蔣介石過(guò)目。老蔣看了氣得大罵:“娘希匹,全都有一股棺材里腐尸的氣味。”我看了幾千頁(yè)的軟件工程資料,終于發(fā)現(xiàn)自己有些“弱智”,無(wú)法理解“面向?qū)ο?#8221;的理論,同時(shí)醒悟到“編程是硬道理。”
面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言很多,如Smalltalk、Ada、Eiffel、Object Pascal、Visual Basic、C++等等。C++語(yǔ)言最討人喜歡,因?yàn)樗嫒軨 語(yǔ)言,并且具備C 語(yǔ)言的性能。近幾年,一種叫Java 的純面向?qū)ο笳Z(yǔ)言紅極一時(shí),不少人叫喊著要用Java 革C++的命。我認(rèn)為Java 好比是C++的外甥,雖然不是直接遺傳的,但也幾分象樣。外甥在舅舅身上玩耍時(shí)灑了一泡尿,倆人不該為此而爭(zhēng)吵。
關(guān)于C++程序設(shè)計(jì)的書藉非常多,本章不講C++的語(yǔ)法,只講一些小小的編程道理。如果我能早幾年明白這些小道理,就可以大大改善數(shù)十萬(wàn)行程序的質(zhì)量了。
1. C++面向?qū)ο蟪绦蛟O(shè)計(jì)的重要概念
早期革命影片里有這樣一個(gè)角色,他說(shuō):“我是黨代表,我代表黨,我就是黨。”后來(lái)他給同志們帶來(lái)了災(zāi)難。
會(huì)用C++的程序員一定懂得面向?qū)ο蟪绦蛟O(shè)計(jì)嗎?
不會(huì)用C++的程序員一定不懂得面向?qū)ο蟪绦蛟O(shè)計(jì)嗎?
兩者都未必。就象壞蛋入黨后未必能成為好人,好人不入黨未必變成壞蛋那樣。
我不怕觸犯眾怒地說(shuō)句大話:“C++沒有高手,C 語(yǔ)言才有高手。”在用C 和C++編程8年之后,我深深地遺憾自己不是C 語(yǔ)言的高手,更遺憾沒有人點(diǎn)撥我如何進(jìn)行面向?qū)ο蟪绦蛟O(shè)計(jì)。我和很多C++程序員一樣,在享用到C++語(yǔ)法的好處時(shí)便以為自己已經(jīng)明白了面向?qū)ο蟪绦蛟O(shè)計(jì)。就象擠掉牙膏賣牙膏皮那樣,真是暴殄天物呀。
人們不懂拼音也會(huì)講普通話,如果懂得拼音則會(huì)把普通話講得更好。不懂面向?qū)ο蟪绦蛟O(shè)計(jì)也可以用C++編程,如果懂得面向?qū)ο蟪绦蛟O(shè)計(jì)則會(huì)把C++程序編得更好。本節(jié)講述三個(gè)非常基礎(chǔ)的概念:“類與對(duì)象”、“繼承與組合”、“虛函數(shù)與多態(tài)”。理解這些概念,有助于提高程序的質(zhì)量,特別是提高“可復(fù)用性”與“可擴(kuò)充性”。
1.1 類與對(duì)象
對(duì)象(Object)是類(Class)的一個(gè)實(shí)例(Instance)。如果將對(duì)象比作房子,那么類就是房子的設(shè)計(jì)圖紙。所以面向?qū)ο蟪绦蛟O(shè)計(jì)的重點(diǎn)是類的設(shè)計(jì),而不是對(duì)象的設(shè)計(jì)。類可以將數(shù)據(jù)和函數(shù)封裝在一起,其中函數(shù)表示了類的行為(或稱服務(wù))。類提供關(guān)鍵字public、protected 和private 用于聲明哪些數(shù)據(jù)和函數(shù)是公有的、受保護(hù)的或者是私有的。
這樣可以達(dá)到信息隱藏的目的,即讓類僅僅公開必須要讓外界知道的內(nèi)容,而隱藏其它一切內(nèi)容。我們不可以濫用類的封裝功能,不要把它當(dāng)成火鍋,什么東西都往里扔。
類的設(shè)計(jì)是以數(shù)據(jù)為中心,還是以行為為中心?
主張“以數(shù)據(jù)為中心”的那一派人關(guān)注類的內(nèi)部數(shù)據(jù)結(jié)構(gòu),他們習(xí)慣上將private 類型的數(shù)據(jù)寫在前面,而將public 類型的函數(shù)寫在后面,如表8.1(a)所示。
主張“以行為為中心”的那一派人關(guān)注類應(yīng)該提供什么樣的服務(wù)和接口,他們習(xí)慣上將public 類型的函數(shù)寫在前面,而將private 類型的數(shù)據(jù)寫在后面,如表8.1(b)所示。

很多C++教課書主張?jiān)谠O(shè)計(jì)類時(shí)“以數(shù)據(jù)為中心”。我堅(jiān)持并且建議讀者在設(shè)計(jì)類時(shí)“以行為為中心”,即首先考慮類應(yīng)該提供什么樣的函數(shù)。Microsoft 公司的COM 規(guī)范的核心是接口設(shè)計(jì),COM 的接口就相當(dāng)于類的公有函數(shù)[Rogerson 1999]。在程序設(shè)計(jì)方面,咱們不要懷疑Microsoft 公司的風(fēng)格。
設(shè)計(jì)孤立的類是比較容易的,難的是正確設(shè)計(jì)基類及其派生類。因?yàn)橛行┏绦騿T搞不清楚“繼承”(Inheritance)、“組合”(Composition)、“多態(tài)”( Polymorphism)這些概念。
1.2 繼承與組合
如果A 是基類,B 是A 的派生類,那么B 將繼承A 的數(shù)據(jù)和函數(shù)。示例程序如下:
class A
{
public:
void Func1(void);
void Func2(void);
};
class B : public A
{
public:
void Func3(void);
void Func4(void);
};
// Example
main()
{
B b; // B的一個(gè)對(duì)象
b.Func1(); // B 從A 繼承了函數(shù)Func1
b.Func2(); // B 從A 繼承了函數(shù)Func2
b.Func3();
b.Func4();
}
這個(gè)簡(jiǎn)單的示例程序說(shuō)明了一個(gè)事實(shí):C++的“繼承”特性可以提高程序的可復(fù)用性。正因?yàn)?#8220;繼承”太有用、太容易用,才要防止亂用“繼承”。我們要給“繼承”立一些使用規(guī)則:
一、如果類A 和類B 毫不相關(guān),不可以為了使B 的功能更多些而讓B 繼承A 的功能。
不要覺得“不吃白不吃”,讓一個(gè)好端端的健壯青年無(wú)緣無(wú)故地吃人參補(bǔ)身體。
二、如果類B 有必要使用A 的功能,則要分兩種情況考慮:
(1)若在邏輯上B 是A 的“一種”(a kind of ),則允許B 繼承A 的功能。如男人(Man)是人(Human)的一種,男孩(Boy)是男人的一種。那么類Man 可以從類Human 派生,類Boy 可以從類Man 派生。示例程序如下:
class Human
{
…
};
class Man : public Human
{
…
};
class Boy : public Man
{
…
};
(2)若在邏輯上A 是B 的“一部分”(a part of),則不允許B 繼承A 的功能,而是要用A和其它東西組合出B。例如眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是頭(Head)的一部分,所以類Head 應(yīng)該由類Eye、Nose、Mouth、Ear 組合而成,不是派生而成。示例程序如下:
class Eye
{
public:
void Look(void);
};
class Nose
{
public:
void Smell(void);
};
class Mouth
{
public:
void Eat(void);
};
class Ear
{
public:
void Listen(void);
};
// 正確的設(shè)計(jì),冗長(zhǎng)的程序
class Head
{
public:
void Look(void) { m_eye.Look(); }
void Smell(void) { m_nose.Smell(); }
void Eat(void) { m_mouth.Eat(); }
void Listen(void) { m_ear.Listen(); }
private:
Eye m_eye;
Nose m_nose;
Mouth m_mouth;
Ear m_ear;
};
如果允許Head 從Eye、Nose、Mouth、Ear 派生而成,那么Head 將自動(dòng)具有Look、Smell、Eat、Listen 這些功能:
// 錯(cuò)誤的設(shè)計(jì)
class Head : public Eye, public Nose, public Mouth, public Ear
{
};
上述程序十分簡(jiǎn)短并且運(yùn)行正確,但是這種設(shè)計(jì)卻是錯(cuò)誤的。很多程序員經(jīng)不起“繼承”的誘惑而犯下設(shè)計(jì)錯(cuò)誤。
一只公雞使勁地追打一只剛下了蛋的母雞,你知道為什么嗎?
因?yàn)槟鸽u下了鴨蛋。
本書3.3 節(jié)講過(guò)“運(yùn)行正確”的程序不見得就是高質(zhì)量的程序,此處就是一個(gè)例證。
1.3 虛函數(shù)與多態(tài)
除了繼承外,C++的另一個(gè)優(yōu)良特性是支持多態(tài),即允許將派生類的對(duì)象當(dāng)作基類的對(duì)象使用。如果A 是基類,B 和C 是A 的派生類,多態(tài)函數(shù)Test 的參數(shù)是A 的 指針。那么Test 函數(shù)可以引用A、B、C 的對(duì)象。示例程序如下:
class A
{
public:
void Func1(void);
};
void Test(A *a)
{
a->Func1();
}
class B : public A
{
…
};
class C : public A
{
…
};
// Example
main()
{
A a;
B b;
C c;
Test(&a);
Test(&b);
Test(&c);
};
以上程序看不出“多態(tài)”有什么價(jià)值,加上虛函數(shù)和抽象基類后,“多態(tài)”的威力就顯示出來(lái)了。
C++用關(guān)鍵字virtual 來(lái)聲明一個(gè)函數(shù)為虛函數(shù),派生類的虛函數(shù)將(override)基類對(duì)應(yīng)的虛函數(shù)的功能。示例程序如下:
class A
{
public:
virtual void Func1(void){ cout<< “This is A::Func1 \n”}
};
void Test(A *a)
{
a->Func1();
}
class B : public A
{
public:
virtual void Func1(void){ cout<< “This is B::Func1 \n”}
};
class C : public A
{
public:
virtual void Func1(void){ cout<< “This is C::Func1 \n”}
};
// Example
main()
{
A a;
B b;
C c;
Test(&a); // 輸出This is A::Func1
Test(&b); // 輸出This is B::Func1
Test(&c); // 輸出This is C::Func1
};
如果基類A 定義如下:
class A
{
public:
virtual void Func1(void)=0;
};
那么函數(shù)Func1 叫作純虛函數(shù),含有純虛函數(shù)的類叫作抽象基類。抽象基類只管定義純虛函數(shù)的形式,具體的功能由派生類實(shí)現(xiàn)。
結(jié)合“抽象基類”和“多態(tài)”有如下突出優(yōu)點(diǎn):
(1)應(yīng)用程序不必為每一個(gè)派生類編寫功能調(diào)用,只需要對(duì)抽象基類進(jìn)行處理即可。這一
招叫“以不變應(yīng)萬(wàn)變”,可以大大提高程序的可復(fù)用性(這是接口設(shè)計(jì)的復(fù)用,而不是代碼實(shí)現(xiàn)的復(fù)用)。
(2)派生類的功能可以被基類指針引用,這叫向后兼容,可以提高程序的可擴(kuò)充性和可維護(hù)性。以前寫的程序可以被將來(lái)寫的程序調(diào)用不足為奇,但是將來(lái)寫的程序可以被以前寫的程序調(diào)用那可了不起。
2.3 new、delete 與指針
在C++中,操作符new 用于申請(qǐng)內(nèi)存,操作符delete 用于釋放內(nèi)存。在C 語(yǔ)言中,函數(shù)malloc 用于申請(qǐng)內(nèi)存,函數(shù)free 用于釋放內(nèi) 存。由于C++兼容C 語(yǔ)言,所以new、delete、malloc、free 都有可能一起使用。new 能比malloc 干更多的事,它可以申請(qǐng)對(duì)象的內(nèi)存,而malloc 不能。C++和C 語(yǔ)言中的指針威猛無(wú)比,用錯(cuò)了會(huì)帶來(lái)災(zāi)難。對(duì)于一個(gè)指針p,如果是用new申請(qǐng)的內(nèi)存,則必須用delete 而不能用free 來(lái)釋放。如果是用malloc 申請(qǐng)的內(nèi)存,則必須用free 而不能用delete 來(lái)釋放。在用delete 或用free 釋放p 所指的內(nèi)存后,應(yīng)該馬上顯式地將p 置為NULL,以防下次使用p 時(shí)發(fā)生錯(cuò)誤。示例程序如下:
void Test(void)
{
float *p;
p = new float[100];
if(p==NULL) return;
…// do something
delete p;
p=NULL; // 良好的編程風(fēng)格
// 可以繼續(xù)使用p
p = new float[500];
if(p==NULL) return;
…// do something else
delete p;
p=NULL;
}
我們還要預(yù)防“野指針”,“野指針”是指向“垃圾”內(nèi)存的指針,主要成因有兩種:
(1)指針沒有初始化。
(2)指針指向已經(jīng)釋放的內(nèi)存,這種情況最讓人防不勝防,示例程序如下:
class A
{
public:
void Func(void){…}
};
void Test(void)
{
A *p;
{
A a;
p = &a; // 注意a 的生命期
}
p->Func(); // p 是“野指針”,程序出錯(cuò)
}
2.4 使用const
在定義一個(gè)常量時(shí),const 比#define 更加靈活。用const 定義的常量含有數(shù)據(jù)類型,該常量可以參與邏輯運(yùn)算。例如:
const int LENGTH = 100; // LENGTH 是int 類型
const float MAX=100; // MAX 是float 類型
#define LENGTH 100 // LENGTH 無(wú)類型
#define MAX 100 // MAX 無(wú)類型
除了能定義常量外,const 還有兩個(gè)“保護(hù)”功能:
一、強(qiáng)制保護(hù)函數(shù)的參數(shù)值不發(fā)生變化
以下程序中,函數(shù)f 不會(huì)改變輸入?yún)?shù)name 的值,但是函數(shù)g 和h 都有可能改變name的值。
void f(String s); // pass by value
void g(String &s); // pass by referance
void h(String *s); // pass by pointer
main()
{
String name=“Dog”;
f(name); // name 的值不會(huì)改變
g(name); // name 的值可能改變
h(name); // name 的值可能改變
}
對(duì)于一個(gè)函數(shù)而言,如果其‘&’或‘*’類型的參數(shù)只作輸入用,不作輸出用,那么應(yīng)當(dāng)在該參數(shù)前加上const,以確保函數(shù)的代碼不會(huì)改變?cè)搮?shù)的值(如果改變了該參數(shù)的值,編譯器會(huì)出現(xiàn)錯(cuò)誤警告)。因此上述程序中的函數(shù)g 和h 應(yīng)該定義成:
void g(const String &s);
void h(const String *s);
二、強(qiáng)制保護(hù)類的成員函數(shù)不改變?nèi)魏螖?shù)據(jù)成員的值
以下程序中,類stack 的成員函數(shù)Count 僅用于計(jì)數(shù),為了確保Count 不改變類中的任何數(shù)據(jù)成員的值,應(yīng)將函數(shù)Count 定義成const 類型。
class Stack
{
public:
void push(int elem);
void pop(void);
int Count(void) const; // const 類型的函數(shù)
private:
int num;
int data[100];
};
int Stack::Count(void) const
{
++ num; // 編譯錯(cuò)誤,num 值發(fā)生變化
pop(); // 編譯錯(cuò)誤,pop 將改變成員變量的值
return num;
}
ATOM 原子(原子表中的一個(gè)字符串的參考)
BOOL 布爾變量
BOOLEAN 布爾變量
BYTE 字節(jié)(8位)
CCHAR Windows字符
CHAR Windows字符
COLORREF 紅、綠、藍(lán)(RGB)彩色值(32位)
Const 變量,該變量的值在執(zhí)行期間保持為常量
CRITICAL_SECTION 臨界段對(duì)象
CTRYID 國(guó)名標(biāo)識(shí)符
DLGPROC 指向一個(gè)對(duì)話框過(guò)程的指針
DWORD 雙字(32位)
ENHMFENUMPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉增強(qiáng)的元文件記錄
ENUMRESLANGPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉資源語(yǔ)言。
ENUMRESNAMEPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉資源名稱。
ENUMRESTYPEPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉資源類型。
FARPROC 指向一個(gè)回調(diào)函數(shù)的指針
FLOAT 浮點(diǎn)變量
FMORDER 32位字體映射值的數(shù)組
FONTENUMPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉字體
GOBJENUMPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉圖形設(shè)備接口(GDI)對(duì)象
HACCEL 加速鍵表句柄
HANDLE 對(duì)象的句柄
HBITMAP 位圖句柄
HBRUSH 畫刷句柄
HCONV 動(dòng)態(tài)數(shù)據(jù)交換(DDE)會(huì)話句柄
HCONVLIST DDE會(huì)話句柄
HCURSOR 光標(biāo)句柄
HDC 設(shè)備描述表(DC)句柄
HDDEDATA DDE數(shù)據(jù)句柄
HDLG 對(duì)話框句柄
HDWP 延期窗口位置結(jié)構(gòu)句柄
HENHMETAFILE 增強(qiáng)原文件句柄
HFILE 文件句柄
HFONT 字體句柄
HGDIOBJ GDI對(duì)象句柄
HGLOBAL 全局內(nèi)存塊句柄
HHOOK 鉤子句柄
HICON 圖標(biāo)句柄
HINSTANCE 實(shí)例句柄
HKEY 登記關(guān)鍵字句柄
HLOCAL 局部?jī)?nèi)存塊句柄
HMEMU 菜單句柄
HMETAFILE 元文件句柄
HMIDIIN 樂器的數(shù)字化接口(MIDI)輸入文件句柄
HMIDIOUT MIDI輸出文件句柄
HMMIO 文件句柄
HOOKPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
HPALETTE 調(diào)色板句柄
HPEN 畫筆句柄
HRGN 域句柄
HRSRC 資源句柄
HSZ DDE字符串句柄
HWAVEIN 波形輸入文件句柄
HWAVEOUT 波形輸出文件句柄
HWINSTA 工作站句柄
HWND 窗口句柄
INT 符號(hào)整數(shù)
LANGID 語(yǔ)言標(biāo)識(shí)符
LCID 所在國(guó)(Locale)標(biāo)識(shí)符
LCTYPE 所在國(guó)類型
LINEDDAPROC 指向一個(gè)回調(diào)函數(shù)的指針,該回調(diào)函數(shù)處理行坐標(biāo)
LONG 32位符號(hào)整數(shù)
LP 指向一個(gè)以"NULL"結(jié)束的Unicode(TM)字符串的指針
LPARAM 32位消息參數(shù)
LPBOOL 指向一個(gè)布爾變量的指針
LPBYTE 指向一個(gè)字節(jié)的指針
LPCCH 指向一個(gè)Windows字符常量的指針
LPCCHOOKPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
LPCFHOOLPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
LPCH 指向一個(gè)Windows字符的指針
LPCOLORREF 指向一個(gè)COLORREF值的指針
LPCRITICAL_SECTION 指向一個(gè)臨界段對(duì)象的指針
LPCSTR 指向一個(gè)以"NULL"結(jié)束的WINDOWS字符串常量的指針
LPCTSTR 指向一個(gè)以"NULL"結(jié)束的Unicode或Windows字符串常量的指針
LPCWCH 指向一個(gè)以"NULL"指向一個(gè)以"NULL"結(jié)束的Unicode字符常量的指針
LPCWSTR 指向一個(gè)以"NULL"指向一個(gè)以"NULL"結(jié)束的Unicode字符串常量的指針
LPDWORD 指向一個(gè)無(wú)符號(hào)雙字(32位)的指針
LPFRHOOLPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
LPHANDLE 指向一個(gè)句柄的指針
LOHANDLER_FUNCTION 指向一個(gè)處理程序函數(shù)的指針
LPHWAVEIN 指向一個(gè)波形輸入文件句柄的指針
LPHWAVEOUT 指向一個(gè)波形輸出文件句柄的指針
LPINT 指向一個(gè)符號(hào)整數(shù)的指針
LPLONG 指向一個(gè)符號(hào)長(zhǎng)整數(shù)(32位)的指針
LPOFNHOOKPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
LPPRINTHOOKPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
LPSETUPHOOKPROC 指向一個(gè)應(yīng)用程序定義的鉤子函數(shù)的指針
LPTSTR 指向一個(gè)以NULL結(jié)束的Unicode或Windows字符串的指針
LRESULT 消息處理的符號(hào)結(jié)果
LPVOID 指向任何類型的指針
LPWSTR 指向一個(gè)以"NULL"結(jié)束的Unicode字符串的指針
LUID 局部唯一的標(biāo)識(shí)符
MCIDEVICEID 媒體控制接口(MCI)設(shè)備標(biāo)識(shí)符
MFENUMPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉元文件記錄
MMRESULT 多媒體消息的處理結(jié)果
NPSTR 指向一個(gè)以"NULL"結(jié)束的Windows字符串的指針
NWPSTR 指向一個(gè)以"NULL"結(jié)束的Unicode字符串的指針
PBOOL 指向一個(gè)布爾變量的指針
PBYTE 指向一個(gè)字節(jié)的指針
PCCH 指向一個(gè)Windows字符常量的指針
PCH 指向一個(gè)Windows字符的指針
PCHAR 指向一個(gè)Windows字符的指針
PCRITICAL_SECTION 指向一個(gè)臨界段對(duì)象的指針
PCSTR 指向一個(gè)以"NULL"結(jié)束的Windows字符串常量的指針
PCWCH 指向一個(gè)Unicode字符常量的指針
PCWSTR 指向一個(gè)以"NULL"結(jié)束的Unicode字符串常量的指針
PDWORD 指向一個(gè)無(wú)符號(hào)雙字的指針
PFLOAT 指向一個(gè)浮點(diǎn)變量的指針
PFNCALLBACK 指向一個(gè)回調(diào)函數(shù)的指針
PHANDLE 指向一個(gè)句柄的指針
PHANDLER_ROUTINE 指向一個(gè)處理程序的指針
PHKEY 指向一個(gè)登記關(guān)鍵字的指針
PINT 指向一個(gè)符號(hào)整數(shù)的指針
PLONG 指向一個(gè)符號(hào)長(zhǎng)整數(shù)的指針
PLUID 指向一個(gè)局部唯一的表示符(LUID)的指針
PROPENUMPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉窗口特征
PSHORT 指向一個(gè)符號(hào)短整數(shù)的指針
PSID 指向一個(gè)加密標(biāo)識(shí)符(SID)的指針
PSTR 指向一個(gè)以"NULL"結(jié)束的Windows字符串的指針
PSZ 指向一個(gè)以"NULL"結(jié)束的Windows字符串的指針
PTCH 指向一個(gè)Windows或Unicode字符的指針
PTCHAR 指向一個(gè)Windows或Unicode字符的指針
PTSTR 指向一個(gè)以"NULL"結(jié)束的Windows或Unicode字符串的指針
PUCHAR 指向一個(gè)無(wú)符號(hào)Windows字符的指針
PUINT 指向一個(gè)無(wú)符號(hào)整數(shù)的指針
PULONG 指向一個(gè)無(wú)符號(hào)長(zhǎng)整數(shù)的指針
PUSHORT 指向一個(gè)無(wú)符號(hào)短整數(shù)的指針
PVOID 指向任何類型的指針
PWCH 指向一個(gè)Unicode字符的指針
PWCHAR 指向一個(gè)Unicode字符的指針
PWORD 指向一個(gè)無(wú)符號(hào)字的指針
PWSTR 指向一個(gè)以"NULL"結(jié)束的Unicode字符串的指針
REGSAM 登記關(guān)鍵字的加密掩碼
SC_HANDLE 服務(wù)句柄
SERVICE_STATUS_HANDLE 服務(wù)狀態(tài)值句柄
SHORT 短整數(shù)
SPHANDLE 指向一個(gè)句柄的指針
TCHAR Unicode或Windows字符
TIMERPROC 指向一個(gè)應(yīng)用程序定義的定時(shí)器回調(diào)函數(shù)的指針
UCHAR 無(wú)符號(hào)Windows字符
UINT 無(wú)符號(hào)整數(shù)
ULONG 無(wú)符號(hào)長(zhǎng)整數(shù)
USHORT 無(wú)符號(hào)短整數(shù)
VOID 任何類型
WCHAR Unicode字符
WNDENUMPROC 指向一個(gè)應(yīng)用程序定義的回調(diào)函數(shù)的指針,該回調(diào)函數(shù)枚舉窗口
WNDPROC 指向一個(gè)應(yīng)用程序定義的窗口過(guò)程的指針
WORD 無(wú)符號(hào)字(16位)
WPARAM 32位消息參數(shù)
YIELDPROC 指向一個(gè)輸出回調(diào)函數(shù)的指針
all是一個(gè)集合,包含所有html對(duì)像的集合,寫一個(gè)程式,可以存取到所有的對(duì)像。像這樣:
<script language="javascript">
var obj="";
for(i=0;i<document.all.length;i++)
obj+=document.all[i].tagName+";";
alert(obj);
</script>
注意要把程式放到</html>之后哦。