-
純虛函數:virtual int func() = 0;不需要去實現函數的時候用。 純虛函數在虛函數列表中存儲的值就是0,他并沒有存儲一個具有實際意義的指針。
含有純虛函數的類叫抽象類。哪怕只含有一個純虛函數也叫抽象類。
抽象類不允許實例化對象。
抽象類的子類也可以是抽象類。
抽象類的子類只有把抽象類當中的所有純虛函數都做了實現,這個子類才可以實例化對象。
查看全部 -
當類中沒有虛函數的時候:
? ? ? ?我們通過類的對象訪問其數據成員,訪問其成員函數;前面已經知道,實例化對象時,只有數據成員的大小,這說明類的成員函數是統一放在內存代碼區的,并且有自己的類名稱空間作為限制,只能自己實例化的對象訪問;所以我們通過對象訪問數據成員,是直接在對象的內存塊中偏移得到;而通過對象訪問成員函數,則是要到代碼區才能訪問到;
當父類與子類之間有重名函數時:
(1)通過子類對象訪問父類該重名函數(于是有了隱藏):
? ? ? ? 父類與子類有重名函數時,這時出現了隱藏,即子類是繼承了父類的該重名函數的,但是將其隱藏了。通過子類對象訪問該函數時,訪問的是子類自己的該函數,如果想要訪問父類的該函數,則要在函數前面加上父類的名稱空間限定;代碼示例如下:父類Person和子類Worker,都有一個同名函數name();通過子類對象worker調用父類該函數時,worker.Person::name();
(2)通過父類指針指向子類對象,并訪問子類重名函數(于是有了虛函數):
? ? ? ? 父類指針指向子類對象時,父類指針只能訪問子類對象的數據成員(部分,繼承自父類的),和訪問父類在代碼區的自己的成員函數;此時,如果想要通過父類指針訪問到子類對象的成員函數(即通過父類指針調用子類的析構函數或者普通重名函數),就要將該重名函數設定為虛函數,然后將虛函數地址放進該類的虛函數表中(于是有了覆蓋,即在子類虛函數表中用子類虛函數地址覆蓋掉父類虛函數地址),而對象又多了個數據成員(虛函數表指針),且在對象內存塊首位;這樣當我們用父類指針指向子類對象,且調用子類重名虛函數時,就要先在虛函數表中查找,如果找到,就執行;即調用成員函數時,有虛函數表先在虛函數表中查找,然后再在代碼區查找;
? ? ? ? 這里我只解釋了父類指針訪問子類重名函數的情況,沒有解釋虛析構函數不重名也能訪問的情況。我想可能是析構函數有自己特殊的用法吧,可能每個類的析構函數都是同一個名字,而在代碼中名字是不同的吧。這里如果有同學想明白了,希望能不吝賜教;
(3)通過子類對象初始化父類對象,通過父類對象不能訪問子類重名函數(虛):
? ? ? ? 按照上面的理論,子類對象初始化父類對象后,子類對象的數據成員會覆蓋掉父類對象的數據成員,但是這里,父類原有的虛函數表是沒有被覆蓋掉的,父類對象的虛函數表指針還是自己的表指針;表指針里的虛函數地址還是父類自己的虛函數地址,所以此時通過父類對象只能訪問到子類對象的數據成員(繼承自父類的),訪問自己代碼區的成員函數和虛函數列表中的自己的虛函數,不能訪問到子類虛函數列表中的虛函數;
查看全部 -
對象的大小
(1)類實例化對象時,對象的大小就是類中數據成員所占的內存大?。〝祿蓡T,不包含成員函數);
(2)若類中存在一個或多個虛函數或虛析構函數,則會在實例對象的前4個B內存單元存放一個虛函數表指針(指針大小為4B);
注意1:每個類只有一個虛函數表,所有該類的對象共用一張虛函數表。
注意2:父類和子類的虛函數表不同,但虛函數表中的函數地址可能相同,指向同一個虛函數地址(這種情況父類虛函數未被子類的覆蓋, 沒有形成多態)
(3)如果類中沒有數據成員或虛函數,則對象大小為1字節,用來標識對象的存在。
查看全部 -
沒有數據成員的類,實例化以后,sizeof后的值是1,原因是C++對于沒有數據成員的對象,C++會用1個內存單元用來標記這個對象
查看全部 -
對象的大?。侯悓嵗膶ο螅瑪祿蓡T占據的內存大小,成員函數不占據內存。
對象的地址:實例化的對象,所占內存的第一個存儲單元的地址
對象成員地址:實例化對象有一個或多個數據成員,每個數據成員都有自己的地址,占一定的內存空間(數據類型不同,地址不同)
虛函數表指針:具有虛函數的類實例化的對象時,對象的第一塊內存中存儲的就是虛函數表指針
查看全部 -
通過虛析構函數,釋放父類指針就能夠釋放子類申請的內存,有個理論前提就是:執行完子類的虛構函數就會執行父類的析構函數。因此只要保證能夠執行子類的虛構函數即可(就相當于子類的和父類的都釋放了。 當然,只有在堆內申請內存才會出現要釋放內存的過程。)
父類指針指向子類的時候,訪問子類的虛函數列表,可以找到子類的虛析構函數,因此釋放父類指針可以執行子類的虛析構函數。反言之, 如果父類和子類的不是虛析構函數,則析構函數不會存在與虛函數列表中,父類指針就找不到子類的析構函數。
查看全部 -
函數的隱藏:定義了父類與子類,且出現了同名的函數,稱為隱藏
函數的覆蓋:若在子類中未定義同名的虛函數,則子類的虛函數表中寫上父類虛函數的入口地址;若在子類中定義了同名的虛函數,則在子類的虛函數表中,子類虛函數入口地址覆蓋原來父類的
查看全部 -
虛函數:假設存在、作為基類方便不同子類派生函數的存在函數。其特點在于,虛函數本身沒有任何意義,其只是作為一個象征:我所有的子類都有如此一個函數存在,至于子類的函數到底如何實現,基類并不知曉。
查看全部 -
函數指針的實質是指向這段函數代碼的開頭位置
查看全部 -
virtual在函數中的使用限制:
·普通函數不能是虛函數(編譯錯誤)
· 靜態成員函數不能是虛函數(編譯錯誤)
·內聯函數不能是虛函數(可編譯,編譯器忽略inline關鍵字是函數變為純粹虛函數)
·構造函數不能是虛函數(編譯錯誤)
查看全部 -
查看全部
-
多態分為兩種 靜態多態和動態多態? 靜態指的就是函數重載(是在一個函數或者一個類中? )? ;而動態多態就是 指的多個類之間的多態??
查看全部 -
使用父類指針指向子類對象時,調用子類完全相同的函數時候 會執行父類函數,需要在父類加virtual關鍵字使父類函數成為虛函數,才能調用子類自己的同名函數
查看全部 -
靜態多態(早綁定):成員函數同名,但參數數目不同時,調用成員函數使用的參數個數決定了啟用不同的成員函數。 /*函數編譯階段就已經確定用哪種行為*/
動態多態(晚綁定):以封裝和繼承為基礎,當父類指針指向子類類型時,要用virtual去修飾子類中已經重定義的成員函數(虛函數),否則使用的是父類的定義的成員函數;子類中的同名成員函數virtual可加可不加,系統默認補全。
”父類指針指向子類對象,通過父類指針只能尋址到從父類繼承到的成員函數與數據成員,子類擴展的將會被截斷。但是,如果將父類中同名函數設置為虛函數,創建子類對象時將會創建子類自有的【虛函數表】,虛函數表指向的成員函數將覆蓋父類中的同名函數?!?/p>
查看全部 -
對不同對象下達相同指令,但是做的不同的操作
查看全部
舉報