靜態(tài)成員變量必須要在類外初始化
type class::name = value;初始化的時(shí)候不用帶static但需要有類型,PRotected,privated,public都可以被這樣初始化
靜態(tài)成員變量的調(diào)用
//通過類類訪問 static 成員變量Student::m_total = 10;//通過對象來訪問 static 成員變量Student stu("小明", 15, 92.5f);stu.m_total = 20;//通過對象指針來訪問 static 成員變量Student *pstu = new Student("李華", 16, 96);pstu -> m_total = 20;static 成員變量不占用對象的內(nèi)存,而是在所有對象之外開辟內(nèi)存,即使不創(chuàng)建對象也可以訪問。一個(gè)類中可以有一個(gè)或多個(gè)靜態(tài)成員變量,所有的對象都共享這些靜態(tài)成員變量,都可以引用它。static 成員變量和普通 static 變量一樣,都在內(nèi)存分區(qū)中的全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存,到程序結(jié)束時(shí)才釋放。這就意味著,static 成員變量不隨對象的創(chuàng)建而分配內(nèi)存,也不隨對象的銷毀而釋放內(nèi)存。而普通成員變量在對象創(chuàng)建時(shí)分配內(nèi)存,在對象銷毀時(shí)釋放內(nèi)存。靜態(tài)成員變量初始化時(shí)可以賦初值,也可以不賦值。如果不賦值,那么會被默認(rèn)初始化為 0。全局?jǐn)?shù)據(jù)區(qū)的變量都有默認(rèn)的初始值 0,而動(dòng)態(tài)數(shù)據(jù)區(qū)(堆區(qū)、棧區(qū))變量的默認(rèn)值是不確定的,一般認(rèn)為是垃圾值。靜態(tài)成員變量既可以通過對象名訪問,也可以通過類名訪問,但要遵循 private、protected 和 public 關(guān)鍵字的訪問權(quán)限限制。當(dāng)通過對象名訪問時(shí),對于不同的對象,訪問的是同一份內(nèi)存。靜態(tài)成員變量可以成為派生類和基類共同使用的數(shù)值,也可以成為成員函數(shù)的可選參數(shù)。靜態(tài)成員變量可以是所屬類的類型,普通數(shù)據(jù)成員只能成為該類的指針或引用。靜態(tài)成員函數(shù)的地址可以用普通函數(shù)指針調(diào)用
class A{public: static fun(){}; int fun1(){};}int (*pf1)()=&base::fun;int (base::*pf2)()=&case::fun1;靜態(tài)成員函數(shù)不可以調(diào)用類的非靜態(tài)成員,因?yàn)檫@個(gè)靜態(tài)成員函數(shù)并不帶有this指針。靜態(tài)成員函數(shù)不可以同時(shí)聲明為 virtual const volatile函數(shù)。靜態(tài)成員函數(shù)不需要對象名即可調(diào)用。非靜態(tài)成員函數(shù)可以自由調(diào)用靜態(tài)成員函數(shù)和靜態(tài)成員變量。調(diào)用時(shí)機(jī)
類作為一個(gè)參數(shù)整體傳入一個(gè)函數(shù)的時(shí)候,需要調(diào)用這個(gè)類的拷貝構(gòu)造函數(shù),進(jìn)行形參和實(shí)參的復(fù)制類作為一個(gè)結(jié)果返回的時(shí)候,先產(chǎn)生一個(gè)臨時(shí)變量,調(diào)用拷貝構(gòu)造函數(shù)將返回值拷貝到臨時(shí)變量,析構(gòu)返回的變量,再析構(gòu)臨時(shí)變量需要通過另一個(gè)變量初始化的時(shí)候
class mode{...}mode A(10);mode B = A;拷貝構(gòu)造函數(shù)分為淺拷貝和深拷貝。默認(rèn)拷貝構(gòu)造函數(shù)是淺拷貝的一種
默認(rèn)拷貝構(gòu)造函數(shù)無法處理靜態(tài)成員變量只是簡單復(fù)制需要自己寫淺拷貝構(gòu)造函數(shù)進(jìn)行靜態(tài)成員變量的復(fù)制如果被拷貝對象中包含指針,進(jìn)行逐位拷貝后新舊兩個(gè)指針將指向同一個(gè)空間,并且將被重復(fù)釋放深拷貝用于需要?jiǎng)討B(tài)創(chuàng)建新空間時(shí)
Rect(const Rect& r) { width = r.width; height = r.height; p = new int; // 為新對象重新動(dòng)態(tài)分配空間 *p = *(r.p); } 可以創(chuàng)建一個(gè)private的拷貝構(gòu)造函數(shù)聲明來解決默認(rèn)值拷貝。???空初始化:即無參數(shù)無括號形式
如int i,new int,new int[10].當(dāng)在所有函數(shù)之外時(shí),初始化為0;當(dāng)在某一函數(shù)中時(shí),沒初始化。值初始化:即無參數(shù)有括號形式,且括號只能在類型名后,而不能在變量名之后,即只能創(chuàng)無名對象,對象被值初始化為0.
如:int() //創(chuàng)建了一個(gè)無名對象,其被值初始化為0.一般將該無名對象初始化化或賦值給某有名對象,或直接作為無名對象使用顯式初始化:即有參數(shù)有括號形式,且當(dāng)為有名對象時(shí)括號在對象名之后,為無名對象時(shí)括號在類類型名之后。
如:int i(5); new int(5);以下四種必須使用初始化列表: 初始化一個(gè)引用成員變量初始化一個(gè)const變量當(dāng)我們在初始化一個(gè)子類對象的時(shí)候,而這個(gè)子類對象的父類有一個(gè)顯示的帶有參數(shù)的構(gòu)造函數(shù)當(dāng)調(diào)用一個(gè)類類型成員的構(gòu)造函數(shù),而它擁有一組參數(shù)的時(shí)候析構(gòu)函數(shù)通常使用默認(rèn)析構(gòu)函數(shù),但是在之前進(jìn)行空間改變(指針移位等)的時(shí)候一定要自己寫析構(gòu)函數(shù)。析構(gòu)數(shù)組或類組:
class A{ A(){m_a=new int[10];} ~A(){delete [] m_a;} int * m_a;}強(qiáng)制類型轉(zhuǎn)換支持但并不推薦,推薦使用以下較溫和的方法:
pd = static_cast<double*>(pv);初始化列表不管怎么寫,初始化的順序也只是按照原類內(nèi)聲明的順序進(jìn)行。兩種重載方式的比較:
一般情況下,單目運(yùn)算符最好重載為類的成員函數(shù);雙目運(yùn)算符則最好重載為類的友元函數(shù)。 以下一些雙目運(yùn)算符不能重載為類的友元函數(shù):=、()、[]、->。
類型轉(zhuǎn)換函數(shù)只能定義為一個(gè)類的成員函數(shù)而不能定義為類的友元函數(shù)。 C++提供4個(gè)類型轉(zhuǎn)換函數(shù):reinterpret_cast(在編譯期間實(shí)現(xiàn)轉(zhuǎn)換)、const_cast(在編譯期間實(shí)現(xiàn)轉(zhuǎn)換)、stactic_cast(在編譯期間實(shí)現(xiàn)轉(zhuǎn)換)、dynamic_cast(在運(yùn)行期間實(shí)現(xiàn)轉(zhuǎn)換,并可以返回轉(zhuǎn)換成功與否的標(biāo)志)。
若一個(gè)運(yùn)算符的操作需要修改對象的狀態(tài),選擇重載為成員函數(shù)較好。
若運(yùn)算符所需的操作數(shù)(尤其是第一個(gè)操作數(shù))希望有隱式類型轉(zhuǎn)換,則只能選用友元函數(shù)。 當(dāng)運(yùn)算符函數(shù)是一個(gè)成員函數(shù)時(shí),最左邊的操作數(shù)(或者只有最左邊的操作數(shù))必須是運(yùn)算符類的一個(gè)類對象(或者是對該類對象的引用)。如果左邊的操作數(shù)必須是一個(gè)不同類的對象,或者是一個(gè)內(nèi)部 類型的對象,該運(yùn)算符函數(shù)必須作為一個(gè)友元函數(shù)來實(shí)現(xiàn)。
當(dāng)需要重載運(yùn)算符具有可交換性時(shí),選擇重載為友元函數(shù)。
注意事項(xiàng):
除了類屬關(guān)系運(yùn)算符”.“、成員指針運(yùn)算符”.*“、作用域運(yùn)算符”::“、sizeof運(yùn)算符和三目運(yùn)算符”?:“以外,C++中的所有運(yùn)算符都可以重載。
重載運(yùn)算符限制在C++語言中已有的運(yùn)算符范圍內(nèi)的允許重載的運(yùn)算符之中,不能創(chuàng)建新的運(yùn)算符。 運(yùn)算符重載實(shí)質(zhì)上是函數(shù)重載,因此編譯程序?qū)\(yùn)算符重載的選擇,遵循函數(shù)重載的選擇原則。
重載之后的運(yùn)算符不能改變運(yùn)算符的優(yōu)先級和結(jié)合性,也不能改變運(yùn)算符操作數(shù)的個(gè)數(shù)及語法結(jié)構(gòu)。
運(yùn)算符重載不能改變該運(yùn)算符用于內(nèi)部類型對象的含義。它只能和用戶自定義類型的對象一起使用,或者用于用戶自定義類型的對象和內(nèi)部類型的對象混合使用時(shí)。
運(yùn)算符重載是針對新類型數(shù)據(jù)的實(shí)際需要對原有運(yùn)算符進(jìn)行的適當(dāng)?shù)母脑欤剌d的功能應(yīng)當(dāng)與原有功能相類似,避免沒有目的地使用重載運(yùn)算符。
繼承
class Human{ …};class Man : public Human{ …};class Boy : public Man{ …};組合
class Eye{ public: void Look(void);};class Nose{ public: void Smell(void);};class Mouth{ public: void Eat(void);};class Ear{ public: void Listen(void);};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;};繼承的關(guān)系不同對這個(gè)派生類并無影響,而是對該派生類的派生類產(chǎn)生影響。例如private Base(10),則對于該派生類的派生類來說,Base不可見。純虛函數(shù):只聲明,無定義,包含純虛函數(shù)的類稱為抽象類,無實(shí)際作用,只作為基類。
class <類名>{virtual <類型><函數(shù)名>(<參數(shù)表>)=0;…};重載和覆蓋的區(qū)別
重載的幾個(gè)函數(shù)必須在同一個(gè)類中; 覆蓋的函數(shù)必須在有繼承關(guān)系的不同的類中覆蓋的幾個(gè)函數(shù)必須函數(shù)名、參數(shù)、返回值都相同; 重載的函數(shù)必須函數(shù)名相同,參數(shù)不同。覆蓋的函數(shù)前必須加關(guān)鍵字Virtual; 重載和Virtual沒有任何瓜葛,加不加都不影響重載的運(yùn)作。關(guān)于C++的隱藏規(guī)則:
如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時(shí),不論有無virtual 關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual 關(guān)鍵字。此時(shí),基類的函數(shù)被隱藏(注意別與覆蓋混淆)。重寫 重載 重定義
重寫(override): 父類與子類之間的多態(tài)性。子類重新定義父類中有相同名稱和參數(shù)的虛函數(shù)。
1) 被重寫的函數(shù)不能是 static 的。必須是 virtual 的 ( 即函數(shù)在最原始的基類中被聲明為 virtual ) 。
2) 重寫函數(shù)必須有相同的類型,名稱和參數(shù)列表 (即相同的函數(shù)原型)
3) 重寫函數(shù)的訪問修飾符可以不同。盡管 virtual 是 private 的,派生類中重寫改寫為 public,protected 也是可以的
重載 (overload): 指函數(shù)名相同,但是它的參數(shù)表列個(gè)數(shù)或順序,類型不同。但是不能靠返回類型來判斷。
重定義 (redefining): 子類重新定義父類中有相同名稱的非虛函數(shù) ( 參數(shù)列表可以不同 ) 。
重寫與重載的區(qū)別 (override) PK (overload)
方法的重寫是子類和父類之間的關(guān)系,是垂直關(guān)系;方法的重載是同一個(gè)類中方法之間的關(guān) 系,是水平關(guān)系。
重寫要求參數(shù)列表相同;重載要求參數(shù)列表不同。
重寫關(guān)系中,調(diào)用那個(gè)方法體,是根據(jù)對象的類型(對象對應(yīng)存儲空間類型)來決定;重載關(guān)系,是根據(jù)調(diào)用時(shí)的實(shí)參表與形參表來選擇方法體的。
對象的動(dòng)態(tài)類型:目前所指對象的類型。是在運(yùn)行期決定的。對象的動(dòng)態(tài)類型可以更改,但是靜態(tài)類型無法更改。
D* pD = new D();//pD的靜態(tài)類型是它聲明的類型D*,動(dòng)態(tài)類型也是D* B* pB = pD;//pB的靜態(tài)類型是它聲明的類型B*,動(dòng)態(tài)類型是pB所指向的對象pD的類型D* C* pC = new C(); pB = pC;//pB的動(dòng)態(tài)類型是可以更改的,現(xiàn)在它的動(dòng)態(tài)類型是C* 靜態(tài)綁定:綁定的是對象的靜態(tài)類型,某特性(比如函數(shù))依賴于對象的靜態(tài)類型,發(fā)生在編譯期。動(dòng)態(tài)綁定:綁定的是對象的動(dòng)態(tài)類型,某特性(比如函數(shù))依賴于對象的動(dòng)態(tài)類型,發(fā)生在運(yùn)行期。只有虛函數(shù)是動(dòng)態(tài)綁定,其余函數(shù)都是靜態(tài)綁定。動(dòng)態(tài)綁定的函數(shù)調(diào)用的函數(shù)體看實(shí)際上的對象類型,靜態(tài)綁定的函數(shù)調(diào)用的函數(shù)體看聲明的對象類型。虛函數(shù)是動(dòng)態(tài)綁定的,但是為了執(zhí)行效率,缺省參數(shù)是靜態(tài)綁定的。對于一個(gè)使用了虛函數(shù)的基類來說:
Base b = d;//直接賦值(產(chǎn)生切割) b.Test(); Base& b2 = d;//使用引用賦值(不產(chǎn)生切割) b2.Test(); Base* b3 = &d;//使用指針賦值(不產(chǎn)生切割) b3->Test(); //覆蓋方法和子類數(shù)據(jù)丟失的現(xiàn)象生成切割(slice)模板的一般形式:
Template <class或者也可以用typename T>返回類型 函數(shù)名(形參表){//函數(shù)定義體 }//template是一個(gè)聲明模板的關(guān)鍵字,表示聲明一個(gè)模板關(guān)鍵字class不能省略,如果類型形參多余一個(gè) ,每個(gè)形參前都要加class <類型 形參表>可以包含基本數(shù)據(jù)類型可以包含類類型.template <class T> inline T square(T x) { T result; result = x * x; return result; };http://m.survivalescaperooms.com/ggjucheng/archive/2011/12/18/2292089.html
explicit可以避免隱式調(diào)用構(gòu)造函數(shù)。
|
新聞熱點(diǎn)
疑難解答
圖片精選