static
控制變量的存儲(chǔ)方式和可見性。
修飾局部變量
一般情況下,對(duì)于局部變量是存放在棧區(qū)的,并且局部變量的生命周期在該語句塊執(zhí)行結(jié)束時(shí)便結(jié)束了。但是如果用static進(jìn)行修飾的話,該變量便存放在靜態(tài)數(shù)據(jù)區(qū),其生命周期一直持續(xù)到整個(gè)程序執(zhí)行結(jié)束。但是在這里要注意的是,雖然用static對(duì)局部變量進(jìn)行修飾過后,其生命周期以及存儲(chǔ)空間發(fā)生了變化,但是其作用域并沒有改變,其仍然是一個(gè)局部變量,作用域僅限于該語句塊。修飾全局變量
對(duì)于一個(gè)全局變量,它既可以在本源文件中被訪問到,也可以在同一個(gè)工程的其它源文件中被訪問(只需用extern進(jìn)行聲明即可)。用static對(duì)全局變量進(jìn)行修飾改變了其作用域的范圍,由原來的整個(gè)工程可見變?yōu)楸驹次募梢姟?/strong>修飾函數(shù)
用static修飾函數(shù)的話,情況與修飾全局變量大同小異,就是改變了函數(shù)的作用域。C++中的static
如果在C++中對(duì)類中的某個(gè)函數(shù)用static進(jìn)行修飾,則表示該函數(shù)屬于一個(gè)類而不是屬于此類的任何特定對(duì)象;如果對(duì)類中的某個(gè)變量進(jìn)行static修飾,表示該變量為類以及其所有的對(duì)象所有。它們?cè)诖鎯?chǔ)空間中都只存在一個(gè)副本??梢酝ㄟ^類和對(duì)象去調(diào)用。
1)類的靜態(tài)成員:
在cpp中必須對(duì)他進(jìn)行初始化,初始化時(shí)使用作用域運(yùn)算符來標(biāo)明他所屬類,其屬于該類的所有成員共有,只有一個(gè)拷貝;
2)類的靜態(tài)成員函數(shù):
類的靜態(tài)函數(shù)是該類的范疇內(nèi)的全局函數(shù),不能訪問類的私有成員,只能訪問類的靜態(tài)成員,不需要類的實(shí)例即可調(diào)用;實(shí)際上,他就是增加了類的訪問權(quán)限的全局函數(shù)
const的含義及實(shí)現(xiàn)機(jī)制
const名叫常量限定符,用來限定特定變量,以通知編譯器該變量是不可修改的。習(xí)慣性的使用const,可以避免在函數(shù)中對(duì)某些不應(yīng)修改的變量造成可能的改動(dòng)。
const修飾基本數(shù)據(jù)類型
const修飾一般常量及數(shù)組
基本數(shù)據(jù)類型,修飾符const可以用在類型說明符前,也可以用在類型說明符后,其結(jié)果是一樣的。在使用這些常量的時(shí)候,只要不改變這些常量的值便好。const修飾指針變量及引用變量&
如果const位于星號(hào)的左側(cè),則const就是用來修飾指針?biāo)赶虻淖兞?,即指針指向?yàn)槌A浚?br> 如果const位于星號(hào)的右側(cè),const就是修飾指針本身,即指針本身是常量。
const應(yīng)用到函數(shù)中
作為參數(shù)的const修飾符
調(diào)用函數(shù)的時(shí)候,用相應(yīng)的變量初始化const常量,則在函數(shù)體中,按照const所修飾的部分進(jìn)行常量化,保護(hù)了原對(duì)象的屬性。
[注意]:參數(shù)const通常用于參數(shù)為指針或引用的情況;作為函數(shù)返回值的const修飾符
聲明了返回值后,const按照"修飾原則"進(jìn)行修飾,起到相應(yīng)的保護(hù)作用。const在類中的用法
不能在類聲明中初始化const數(shù)據(jù)成員。正確的使用const實(shí)現(xiàn)方法為:const數(shù)據(jù)成員的初始化只能在類構(gòu)造函數(shù)的初始化表中進(jìn)行const 修飾類成員函數(shù),其目的是防止成員函數(shù)修改被調(diào)用對(duì)象的值,如果我們不想修改一個(gè)調(diào)用對(duì)象的值,所有的成員函數(shù)都應(yīng)當(dāng)聲明為const成員函數(shù)。 其意義上是不能修改所在類的的任何變量。注意:const關(guān)鍵字不能與static關(guān)鍵字同時(shí)使用,因?yàn)閟tatic關(guān)鍵字修飾靜態(tài)成員函數(shù),靜態(tài)成員函數(shù)不含有this指針,即不能實(shí)例化,const成員函數(shù)必須具體到某一實(shí)例。
const修飾類對(duì)象,定義常量對(duì)象
常量對(duì)象只能調(diào)用常量函數(shù),別的成員函數(shù)都不能調(diào)用。
http://www.cnblogs.com/wintergrass/archive/2011/04/15/2015020.html
1)const成員函數(shù)可以訪問非const對(duì)象的非const數(shù)據(jù)成員、const數(shù)據(jù)成員,也可以訪問const對(duì)象內(nèi)的所有數(shù)據(jù)成員;
2)非const成員函數(shù)可以訪問非const對(duì)象的非const數(shù)據(jù)成員、const數(shù)據(jù)成員,但不可以訪問const對(duì)象的任意數(shù)據(jù)成員;
3)作為一種良好的編程風(fēng)格,在聲明一個(gè)成員函數(shù)時(shí),若該成員函數(shù)并不對(duì)數(shù)據(jù)成員進(jìn)行修改操作,應(yīng)盡可能將該成員函數(shù)聲明為const 成員函數(shù)。
static, const 和 static const 變量的初始化問題
const 常量的在超出其作用域的時(shí)候會(huì)被釋放,但是 static 靜態(tài)變量在其作用域之外并沒有釋放,只是不能訪問。
static 修飾的是靜態(tài)變量,靜態(tài)函數(shù)。對(duì)于類來說,靜態(tài)成員和靜態(tài)函數(shù)是屬于整個(gè)類的,而不是屬于對(duì)象??梢酝ㄟ^類名來訪問,但是其作用域限制于包含它的文件中。
static 變量在類內(nèi)部聲明,但是必須在類的外部進(jìn)行定義和初始化。
const 常量在類內(nèi)部聲明,但是定義只能在構(gòu)造函數(shù)的初始化列表進(jìn)行。
虛函數(shù): 虛函數(shù)的作用和實(shí)現(xiàn)原理,什么是虛函數(shù),有什么作用?
C++的多態(tài)分為靜態(tài)多態(tài)(編譯時(shí)多態(tài))和動(dòng)態(tài)多態(tài)(運(yùn)行時(shí)多態(tài))兩大類。靜態(tài)多態(tài)通過重載、模板來實(shí)現(xiàn);動(dòng)態(tài)多態(tài)就是通過本文的主角虛函數(shù)來體現(xiàn)的。
- 虛函數(shù)實(shí)現(xiàn)原理:包括虛函數(shù)表、虛函數(shù)指針等
虛函數(shù)就是對(duì)父類同名函數(shù)的重寫。在成員函數(shù)聲明前面加上virtual修飾,就變成了虛函數(shù)。調(diào)用函數(shù)的哪個(gè)版本只有在運(yùn)行時(shí)才能確定(動(dòng)態(tài)綁定),因此需要虛函數(shù)表,也就導(dǎo)致虛函數(shù)會(huì)比普通函數(shù)成員所花費(fèi)的時(shí)間和空間要多一些。
虛函數(shù)的作用說白了就是:當(dāng)調(diào)用一個(gè)虛函數(shù)時(shí),被執(zhí)行的代碼必須和調(diào)用函數(shù)的對(duì)象的動(dòng)態(tài)類型相一致。編譯器需要做的就是如何高效的實(shí)現(xiàn)提供這種特性。不同編譯器實(shí)現(xiàn)細(xì)節(jié)也不相同。大多數(shù)編譯器通過vtbl(virtual table)和vptr(virtual table pointer)來實(shí)現(xiàn)的。 當(dāng)一個(gè)類聲明了虛函數(shù)或者繼承了虛函數(shù),這個(gè)類就會(huì)有自己的vtbl。vtbl實(shí)際上就是一個(gè)函數(shù)指針數(shù)組,有的編譯器用的是鏈表,不過方法都是差不多。vtbl數(shù)組中的每一個(gè)元素對(duì)應(yīng)一個(gè)函數(shù)指針指向該類的一個(gè)虛函數(shù),同時(shí)該類的每一個(gè)對(duì)象都會(huì)包含一個(gè)vptr,vptr指向該vtbl的地址。
虛函數(shù)不能是構(gòu)造函數(shù),不能是靜態(tài)函數(shù),不能是內(nèi)聯(lián)函數(shù),可以是析構(gòu)函數(shù)。
-
結(jié)論:
1)每個(gè)聲明了虛函數(shù)或者繼承了虛函數(shù)的類,都會(huì)有一個(gè)自己的vtbl,同時(shí)該類的每個(gè)對(duì)象都會(huì)包含一個(gè)vptr去指向該vtbl
2)虛函數(shù)按照其聲明順序放于vtbl表中, vtbl數(shù)組中的每一個(gè)元素對(duì)應(yīng)一個(gè)函數(shù)指針指向該類的虛函數(shù)
3)如果子類覆蓋了父類的虛函數(shù),將被放到了虛表中原來父類虛函數(shù)的位置
4)在多繼承的情況下,每個(gè)父類都有自己的虛表。子類的成員函數(shù)被放到了第一個(gè)父類的表中
C++中引用和指針的區(qū)別
它們都是地址的概念,其中指針指向一塊內(nèi)存,它的內(nèi)容是所指內(nèi)存的地址;而引用是某塊內(nèi)存的別名,具體來說,指針是一個(gè)變量的地址,引用是一個(gè)變量的別名。
但它們的不同之處也很明顯,體現(xiàn)在以下方面:
- 指針是一個(gè)實(shí)體,而引用僅是個(gè)別名;
- 引用必須被初始化,指針不必;
- 引用只能在定義時(shí)被初始化一次,之后不可變;指針可以改變所指的對(duì)象;
- 可以有const指針,但是沒有const引用;
- 不存在指向空值的引用,但是存在指向空值的指針,即引用不能為空,指針可以為空;
- “sizeof 引用”得到的是所指向的變量(對(duì)象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或?qū)ο蟮牡刂罚┑拇笮。?/li>
- 指針和引用的自增(++)運(yùn)算意義不一樣;
- 程序?yàn)橹羔樧兞糠峙鋬?nèi)存區(qū)域,而引用不需要分配內(nèi)存區(qū)域;
內(nèi)存分配:
- 內(nèi)存分配方式有三種:
(1)從靜態(tài)存儲(chǔ)區(qū)域分配。內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好,這塊內(nèi)存在程序的整個(gè)運(yùn)行期間都存在。例如全局變量,static變量。
(2)在棧上創(chuàng)建。在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
(3)從堆上分配,亦稱動(dòng)態(tài)內(nèi)存分配。 程序在運(yùn)行的時(shí)候用malloc或new申請(qǐng)任意多少的內(nèi)存,程序員自己負(fù)責(zé)在何時(shí)用free或delete釋放內(nèi)存。動(dòng)態(tài)內(nèi)存的生存期由我們決定,使用非常靈活,但問題也最多。
STL原理及實(shí)現(xiàn): STL各類型容器實(shí)現(xiàn),STL共有六大組件
STL提供六大組件,彼此可以組合套用:
- 容器(Containers):各種數(shù)據(jù)結(jié)構(gòu),如:序列式容器vector、list、deque、關(guān)聯(lián)式容器set、map、multiset、multimap。用來存放數(shù)據(jù)。從實(shí)現(xiàn)的角度來看,STL容器是一種class template。
- 算法(algorithms):各種常用算法,如:sort、search、copy、erase。從實(shí)現(xiàn)的角度來看,STL算法是一種 function template。注意一個(gè)問題:任何的一個(gè)STL算法,都需要獲得由一對(duì)迭代器所標(biāo)示的區(qū)間,用來表示操作范圍。這一對(duì)迭代器所標(biāo)示的區(qū)間都是前閉后開區(qū)間,例如[first, last)
- 迭代器(iterators):容器與算法之間的膠合劑,是所謂的“泛型指針”。共有五種類型,以及其他衍生變化。從實(shí)現(xiàn)的角度來看,迭代器是一種將 operator*、operator->、operator++、operator- - 等指針相關(guān)操作進(jìn)行重載的class template。所有STL容器都有自己專屬的迭代器,只有容器本身才知道如何遍歷自己的元素。原生指針(native pointer)也是一種迭代器。
- 仿函數(shù)(functors):行為類似函數(shù),可作為算法的某種策略(policy)。從實(shí)現(xiàn)的角度來看,仿函數(shù)是一種重載了operator()的class或class template。一般的函數(shù)指針也可視為狹義的仿函數(shù)。
- 配接器(adapters):一種用來修飾容器、仿函數(shù)、迭代器接口的東西。例如:STL提供的queue 和 stack,雖然看似容器,但其實(shí)只能算是一種容器配接器,因?yàn)樗鼈兊牡撞客耆柚鷇eque,所有操作都由底層的deque供應(yīng)。改變 functors接口者,稱為function adapter;改變 container 接口者,稱為container adapter;改變iterator接口者,稱為iterator adapter。
- 配置器(allocators):負(fù)責(zé)空間配置與管理。從實(shí)現(xiàn)的角度來看,配置器是一個(gè)實(shí)現(xiàn)了動(dòng)態(tài)空間配置、空間管理、空間釋放的class template。
這六大組件的交互關(guān)系:container(容器) 通過 allocator(配置器) 取得數(shù)據(jù)儲(chǔ)存空間,algorithm(算法)通過 iterator(迭代器)存取 container(容器) 內(nèi)容,functor(仿函數(shù)) 可以協(xié)助 algorithm(算法) 完成不同的策略變化,adapter(配接器) 可以修飾或套接 functor(仿函數(shù))
- 序列式容器:
- vector-數(shù)組,元素不夠時(shí)再重新分配內(nèi)存,拷貝原來數(shù)組的元素到新分配的數(shù)組中。
- list-單鏈表。
- deque-分配中央控制器map(并非map容器),map記錄著一系列的固定長度的數(shù)組的地址.記住這個(gè)map僅僅保存的是數(shù)組的地址,真正的數(shù)據(jù)在數(shù)組中存放著.deque先從map中央的位置(因?yàn)殡p向隊(duì)列,前后都可以插入元素)找到一個(gè)數(shù)組地址,向該數(shù)組中放入數(shù)據(jù),數(shù)組不夠時(shí)繼續(xù)在map中找空閑的數(shù)組來存數(shù)據(jù)。當(dāng)map也不夠時(shí)重新分配內(nèi)存當(dāng)作新的map,把原來map中的內(nèi)容copy的新map中。所以使用deque的復(fù)雜度要大于vector,盡量使用vector。
- stack-基于deque。
- queue-基于deque。
- heap-完全二叉樹,使用最大堆排序,以數(shù)組(vector)的形式存放。
- priority_queue-基于heap。
- slist-雙向鏈表。
-
關(guān)聯(lián)式容器:
- set,map,multiset,multimap-基于紅黑樹(RB-tree),一種加上了額外平衡條件的二叉搜索樹。
- hash table-散列表。將待存數(shù)據(jù)的key經(jīng)過映射函數(shù)變成一個(gè)數(shù)組(一般是vector)的索引,例如:數(shù)據(jù)的key%數(shù)組的大?。綌?shù)組的索引(一般文本通過算法也可以轉(zhuǎn)換為數(shù)字),然后將數(shù)據(jù)當(dāng)作此索引的數(shù)組元素。有些數(shù)據(jù)的key經(jīng)過算法的轉(zhuǎn)換可能是同一個(gè)數(shù)組的索引值(碰撞問題,可以用線性探測(cè),二次探測(cè)來解決),STL是用開鏈的方法來解決的,每一個(gè)數(shù)組的元素維護(hù)一個(gè)list,他把相同索引值的數(shù)據(jù)存入一個(gè)list,這樣當(dāng)list比較短時(shí)執(zhí)行刪除,插入,搜索等算法比較快。
- hash_map,hash_set,hash_multiset,hash_multimap-基于hashtable。