//站點(diǎn):www. //所有稿件均有版權(quán),如要轉(zhuǎn)載,請(qǐng)務(wù)必著名出處和作者 class test { private: int number; public: float socre; public: int rp() { return number; } void setnum(int a) { number=a; } }; 但是大家注意到?jīng)]有,標(biāo)準(zhǔn)c中是不允許在結(jié)構(gòu)體中聲明函數(shù)的,但c++中的類可以,這一點(diǎn)就和c有了本質(zhì)的區(qū)別,很好的體現(xiàn)了c++面向?qū)ο蟮奶攸c(diǎn)! 過去的c語(yǔ)言是一種非面向?qū)ο蟮恼Z(yǔ)言 他的特性是 程序=算法+數(shù)據(jù)結(jié)構(gòu) 但c++的特性是 對(duì)象=算法+數(shù)據(jù)結(jié)構(gòu) 程序=對(duì)象+對(duì)象+對(duì)象+對(duì)象+........ 所以根據(jù)這一特性,我們?cè)诙x一個(gè)自己定義的結(jié)構(gòu)體變量的時(shí)候,這個(gè)變量就應(yīng)該是叫做對(duì)象或者叫實(shí)例 例如 test a; 那么a就是test結(jié)構(gòu)的一個(gè)對(duì)象(實(shí)例) test結(jié)構(gòu)體內(nèi)的成員可以叫做是分量,例如: a.socre=10.1f; 那么number就是test結(jié)構(gòu)的對(duì)象a的分量(或者叫數(shù)據(jù)成員,或者叫屬性)score; 在c語(yǔ)言中結(jié)構(gòu)體中的各成員他們的默認(rèn)存儲(chǔ)控制是public 而 c++中類的默認(rèn)存儲(chǔ)控制是private,所以在類中的成員如果需要外部掉用一定要加上關(guān)鍵字public聲明成公有類型,這一特性同樣使用于類中的成員函數(shù),函數(shù)的操作方式和普通函數(shù)差別并不大 例如上面的例子中的rp()成員函數(shù),我們?nèi)绻视腥缦露x test a; 的話,調(diào)用rp()就應(yīng)該寫成 a.rp(); 成員函數(shù)的調(diào)用和普通成員變量的調(diào)用方式一致都采用.的操作符。 這一小節(jié)為了鞏固聯(lián)系我給出一個(gè)完整的例子。 如下(重要和特殊的地方都有詳細(xì)的注解): //程序作者:管寧 //站點(diǎn):www. //所有稿件均有版權(quán),如要轉(zhuǎn)載,請(qǐng)務(wù)必著名出處和作者 #include <iostream> using namespace std; class test { private://私有成員類外不能夠直接訪問 int number; public://共有成員類外能夠直接訪問 float socre; public: int rp() { return number; } void setnum(int a) { number=a; } }; void main() { test a; //a.number=10;//錯(cuò)誤的,私有成員不能外部訪問 a.socre=99.9f; cout<<a.socre<<endl;//公有成員可以外部訪問 a.setnum(100);//通過公有成員函數(shù)setnum()間接對(duì)私有成員number進(jìn)行賦值操作 cout<<a.rp();//間接返回私有成員number的值 cin.get(); } 好了,介紹了在類內(nèi)部定義成員函數(shù)(方法)的方法,下面我們要介紹一下域區(qū)分符(::)的作用了。 下面我們來看一個(gè)例子,利用這個(gè)例子中我們要說明兩個(gè)重要問題: //程序作者:管寧 //站點(diǎn):www. //所有稿件均有版權(quán),如要轉(zhuǎn)載,請(qǐng)務(wù)必著名出處和作者 #include <iostream> using namespace std; int pp=0; class test { private: int number; public: float socre; int pp; public: void rp(); }; void test::rp()//在外部利用域區(qū)分符定義test類的成員函數(shù) { ::pp=11;//變量名前加域區(qū)分符給全局變量pp賦值 pp=100;//設(shè)置結(jié)構(gòu)體變量 } void main() { test a; test b; a.rp(); cout<<pp<<endl; cout<<a.pp<<endl; cin.get(); } 問題1: 利用域區(qū)分符我們可以在類定義的外部設(shè)置成員函數(shù),但要注意的是,在類的內(nèi)部必須預(yù)先聲明: void test::rp() 在函數(shù)類型的后面加上類的名稱再加上域區(qū)分符(::)再加函數(shù)名稱,利用這樣的方法我們就在類的外部建立了一個(gè)名為rp的test類大成員函數(shù)(方法),可能很多人要問,這么做有意義嗎?在類的內(nèi)部寫函數(shù)代碼不是更好? 答案是這樣的:在類的定義中,一般成員函數(shù)的規(guī)模一般都比較小,而且一些特殊的語(yǔ)句是不能夠使用的,而且一般會(huì)被自動(dòng)的設(shè)置成為inline(內(nèi)聯(lián))函數(shù),即使你沒有明確的聲明為inline,那么為什么有會(huì)被自動(dòng)設(shè)置成為inline呢?因?yàn)榇蠖鄶?shù)情況下,類的定義一般是放在頭文件中的,在編譯的時(shí)候這些函數(shù)的定義也隨之進(jìn)入頭文件,這樣就會(huì)導(dǎo)致被多次編譯,如果是inline的情況,函數(shù)定義在調(diào)用處擴(kuò)展,就避免了重復(fù)編譯的問題,而且把大量的成員函數(shù)都放在類中使用起來也十分不方便,為了避免這種情況的發(fā)生,所以c++是允許在外部定義類的成員函數(shù)(方法)的,將類定義和其它成員函數(shù)定義分開,是面向?qū)ο缶幊痰耐ǔW龇ǎ覀儼杨惖亩x在這里也就是頭文件了看作是類的外部接口,類的成員函數(shù)的定義看成是類的內(nèi)部實(shí)現(xiàn)。寫程序的時(shí)候只需要外部接口也就是頭文件即可,這一特點(diǎn)和我們使用標(biāo)準(zhǔn)庫(kù)函數(shù)的道理是一致的,因?yàn)樵陬惖亩x中,已經(jīng)包含了成員函數(shù)(方法)的聲明。 問題二 域區(qū)分符和外部全局變量和類成員變量之間的關(guān)系。 在上面的代碼中我們看到了,外部全局和類內(nèi)部都有一個(gè)叫做pp的整形變量,那么我們要區(qū)分操作他們用什么方法呢? 使用域區(qū)分符就可以做到這一點(diǎn),在上面的代碼中::pp=11;操作的就是外部的同名稱全局變量,pp=100;操作的就是類內(nèi)部的成員變量,這一點(diǎn)十分重要! 問題三 一個(gè)類的所有對(duì)象調(diào)用的都是同一段代碼,那么操作成員變量的時(shí)候計(jì)算機(jī)有是如何知道哪個(gè)成員是屬于哪個(gè)對(duì)象的呢? 這里牽扯到一個(gè)隱藏的this指針的問題,上面的代碼在調(diào)用a.rp()的的時(shí)候,系統(tǒng)自動(dòng)傳遞一了個(gè)a對(duì)象的指針給函數(shù),在內(nèi)部的時(shí)候pp=100;的時(shí)候其實(shí)就是this->pp=100; 所以你把上面的成員函數(shù)寫成如下形勢(shì)也是正確的: void test::rp() { ::pp=11; this->pp=100;//this指針就是指向a對(duì)象的指針 } 類的成員函數(shù)和普通函數(shù)一樣是可以進(jìn)行重載操作的,關(guān)于重載函數(shù)前面已經(jīng)說過,這里不再說明。 給出例子仔細(xì)看: //程序作者:管寧 //站點(diǎn):www. //所有稿件均有版權(quán),如要轉(zhuǎn)載,請(qǐng)務(wù)必著名出處和作者 #include <iostream> using namespace std; class test { private: int number; public: float socre; int pp; public: void rp(int); void rp(float); }; void test::rp(int a)//在外部利用域區(qū)分符定義test類的成員函數(shù) { cout<<"調(diào)用成員函數(shù)!a:"<<a<<endl; } void test::rp(float a)//在外部利用域區(qū)分符定義test類的成員函數(shù) { cout<<"調(diào)用成員函數(shù)!a:"<<a<<endl; } void main() { test a; a.rp(100); a.rp(3.14f); cin.get(); } 下面我們來看一下利用指針和利用引用間接調(diào)用類的成員函數(shù),對(duì)于對(duì)于指針和引用調(diào)用成員函數(shù)和調(diào)用普通函數(shù)差別不大,在這里也就不再重復(fù)說明了,注意看代碼,多試多練習(xí)既可。 代碼如下: //程序作者:管寧 //站點(diǎn):www. //所有稿件均有版權(quán),如要轉(zhuǎn)載,請(qǐng)務(wù)必著名出處和作者 #include <iostream> using namespace std; class test { private: int number; public: float socre; int pp; public: int rp(int); }; int test::rp(int a)//在外部利用域區(qū)分符定義test類的成員函數(shù) { number=100; return a + number; } void run(test *p)//利用指針調(diào)用 { cout<<p->rp(100)<<endl; } void run(test &p)//利用引用 { cout<<p.rp(200)<<endl; } void main() { test a; run(&a); run(a); cin.get(); } 前面我們說過,類的成員如果不顯式的生命為public那么它默認(rèn)的就是private就是私有的,私有聲明可以保護(hù)成員不能夠被外部訪問,但在c++還有一個(gè)修飾符,它具有和private相似的性能,它就是protected修飾符。 在這里我們簡(jiǎn)單說明一下,他們?nèi)g的差別: 在類的private:節(jié)中聲明的成員(無論數(shù)據(jù)成員或是成員函數(shù))僅僅能被類的成員函數(shù)和友元訪問。 在類的protected: 節(jié)中聲明的成員(無論數(shù)據(jù)成員或是成員函數(shù))僅僅能被類的成員函數(shù),友元以及子類的成員函數(shù)和友元訪問。 在類的public:節(jié)中聲明的成員(無論數(shù)據(jù)成員或是成員函數(shù))能被任何人訪問。 由于private和protected的差別主要是體現(xiàn)在類的繼承中,現(xiàn)在的教程還沒有設(shè)計(jì)到友元和子類所以這里不做深入討論,但上面的三點(diǎn)務(wù)必記得,在以后的教程中我們會(huì)回過頭來說明的。 總的來說,類成員的保護(hù)無非是為了以下四點(diǎn)! 1.相對(duì)與普通函數(shù)和其它類的成員函數(shù)來說,保護(hù)類的數(shù)據(jù)不能夠被肆意的篡改侵犯! 2.使類對(duì)它本身的內(nèi)部數(shù)據(jù)維護(hù)負(fù)責(zé),只有類自己才能夠訪問自己的保護(hù)數(shù)據(jù)! 3.限制類的外部接口,把一個(gè)類分成公有的和受保護(hù)的兩部分,對(duì)于使用者來說它只要會(huì)用就可以,無須了解內(nèi)部完整結(jié)構(gòu),起到黑盒的效果。 4.減少類與其它代碼的關(guān)聯(lián)程,類的功能是獨(dú)立的,不需要依靠應(yīng)用程序的運(yùn)行環(huán)境,這個(gè)程序可以用它,另外一個(gè)也可以用它,使得你可以輕易的用一個(gè)類替換另一個(gè)類。 下面為了演示類成員的保護(hù)特性,我們來做一個(gè)球類游戲! 我們?cè)O(shè)計(jì)一個(gè)類,來計(jì)算球員的平均成績(jī),要求在外部不能夠隨意篡改球員的平均成績(jī)。 我們把該類命名為ballscore并且把它放到ballscore.h的有文件中! --------------------------- ballscore.h----------------------------- class ballscore { protected: const static int gbs = 5;//好球單位得分 const static int bbs = -3;//壞球單位扣分 float gradescore;//平均成績(jī) public: float GetGS(float goodball,float badball)//goodball為好球數(shù)量,badball為壞求數(shù)量 { gradescore = (goodball*gbs + badball*bbs) / (goodball + badball); return gradescore;//返回平均成績(jī) } }; -------------------------------------------------------------------- 主函數(shù)調(diào)用! #include <iostream> #include "ballscore.h" using namespace std; void main() { ballscore jeff; cout<<jeff.GetGS(10,3); jeff.gradescore=5.5//想篡改jeff的平均成績(jī)是錯(cuò)誤的! cin.get(); } 在上面的代碼中頭文件和類的使用很好了體現(xiàn)了類的黑盒特性,誰(shuí)也不能夠在外部修改球員的平均成績(jī)! 類體中的有一個(gè)地方要注意 const static int gbs = 5;//好球單位得分 const static int bbs = -3;//壞球單位扣分 之所以要修飾成const static 因?yàn)閏++中類成員只有靜態(tài)整形的常量才能夠被初始化,到這里整個(gè)程序也就說完了,當(dāng)然真正大比賽不可能是這樣,只是為了說明問題就題命題而已,呵呵! 下面我們說一下關(guān)于類的作用域。 在說內(nèi)容之前我們先給出這部分內(nèi)容的一個(gè)完整代碼,看講解的是參照此一下代碼! //程序作者:管寧 //站點(diǎn):www. //所有稿件均有版權(quán),如要轉(zhuǎn)載,請(qǐng)務(wù)必著名出處和作者 #include <iostream> using namespace std; class ballscore { protected: const static int gbs = 5;//好球單位得分 const static int bbs = -3;//壞球單位扣分 float gradescore;//平均成績(jī) public: float GetGS(float goodball,float badball)//goodball為好球數(shù)量,badball為壞求數(shù)量 { int gradescore=0;//新定義一個(gè)和成員變量float gradescore相同名字的類成員函數(shù)局部變量 ballscore::gradescore = (goodball*gbs + badball*bbs) / (goodball + badball);//由于局部變量與類成員變量同名使用的時(shí)候必須在其前加上類名和域區(qū)分符 return ballscore::gradescore;//返回平均成績(jī) } }; int ballscore=0;//定義一個(gè)與類名稱相同的普通全局變量 int test; void main() { class test//局部類的創(chuàng)建 { float a; float b; }; test test; ::test=1;//由于局部類名隱藏了外部變量使用需加域區(qū)分符 class ballscore jeff;//由于全局變量int ballsocre和類(ballsocre)名稱相同,隱藏了類名稱,這時(shí)候定義類對(duì)象需加class前綴以區(qū)分 cout<<jeff.GetGS(10,3); cin.get(); } 類的作用域是只指定義和相應(yīng)的成員函數(shù)定義的范圍,在該范圍內(nèi),一個(gè)類的成員函數(shù)對(duì)同一類的數(shù)據(jù)成員具有無限制的訪問權(quán)。 在類的使用中,我們經(jīng)常會(huì)碰到以下三種情況: 1.類的成員函數(shù)的局部變量隱藏了類的同名成員變量,看如對(duì)上面程序的分析。 protected: const static int gbs = 5; const static int bbs = -3; float gradescore; public: float GetGS(float goodball,float badball) { int gradescore=0; ballscore::gradescore = (goodball*gbs + badball*bbs) / (goodball + badball); return ballscore::gradescore; } 代碼中的int gradescore就把float gradescore給隱藏了,所以要使用成員變量float gradescore的時(shí)候必須在其之前加上類名稱和域區(qū)分符(::)。 2.在類定義外部非類型名隱藏了類型名稱的情況,看上面代碼的分析! class ballscore { protected: const static int gbs = 5; const static int bbs = -3; float gradescore; public: float GetGS(float goodball,float badball) { int gradescore=0; ballscore::gradescore = (goodball*gbs + badball*bbs) / (goodball + badball); return ballscore::gradescore; } }; int ballscore=0; 代碼中的全部變量int ballscore隱藏了類名稱class ballscore 所以在main中如如果要定義ballscore類的對(duì)象就要在類名稱前加上class關(guān)鍵字 class ballscore jeff; 3.類型名稱隱藏了非類型名稱,看對(duì)上面代碼的分析! int test; void main() { class test { float a; float b; }; test test; ::test=1; class ballscore jeff; cout<<jeff.GetGS(10,3); cin.get(); } 在普通函數(shù)內(nèi)部定義的類叫做局部類,代碼中的test類就是一個(gè)局部類! 代碼中的test類隱藏了全局變量test如果要操作全局變量test那么就要在test前加上域區(qū)分符號(hào)(::),進(jìn)行使用! ::test=1就是對(duì)全局變量test進(jìn)行了賦值操作! 我們最后說一下名字空間! 名字空間就是指某一個(gè)名字在其中必須是唯一的作用域. 如果這個(gè)定義想不明白,可以簡(jiǎn)單的說成,在一個(gè)區(qū)域內(nèi),某一個(gè)名字在里面使用必須是唯一的,不能出現(xiàn)重復(fù)定義的情況出現(xiàn),這個(gè)區(qū)域就是名字空間! c++規(guī)定: 1.一個(gè)名字不能同時(shí)設(shè)置為兩種不同的類型 class test { //... }; typedef int test; 這個(gè)就是錯(cuò)誤的! 2.非類型名(變量名,常量名,函數(shù)名,對(duì)象名,枚舉成員)不能重名. test a; void a(); 就是錯(cuò)誤的,因?yàn)閍是一個(gè)test類的對(duì)象,它和函數(shù)a名稱重名了! 3.類型與非類型不在同一個(gè)名字空間上,可以重名,即使在同一作用域內(nèi),但兩者同時(shí)出現(xiàn)時(shí)定義類對(duì)象的時(shí)候要加上前綴class以區(qū)分類型和非類型名! class test { //..... } int test class test a;//利用class前墜區(qū)分,定義了一個(gè)test類的對(duì)象a 好了,到這里關(guān)于類的知識(shí)點(diǎn)我們已經(jīng)學(xué)習(xí)完,希望大家多多練習(xí) |
|