C++基礎知識點

  delete p;只是刪除指針p指向內存區,並不是刪除指針p,所以p還是可以用的。刪除空指針所指向內存是可以的。

  堆中的變量和對象時匿名的,沒有名稱,只能通過指針來訪問。

  在堆中創建對象時,在分配內存的同時會調用類的構造函數,在刪除堆中對象時,會調用類的析構函數。

  爲了避免內存泄露,在刪除一個指針後應該將其其值賦爲0。

  常量指針是指針指向的內存區域地址不能改變,但是該內存地址裏保存的值是可以改變的,比如int a; int * const p = &a;

  指向常量的指針表示指針指向的對象是不能被修改的,但是該指針可以被修改,即該指針可以指向另一塊目標內存地址。比如const int a = 0; const int *p = &a; 如果A是一個類,也可以爲const A* p = new A;

  而指向常量的常指針表示指針本身不能被修改,其指向的內存地址內容也不能被修改。比如const int a = 0; const int * const p = &a;

  引用就是別名常量。

  堆中的地址是用指針來操作的,用不到別名。

  如果在main函數前面的其它函數的聲明和定義是一起的,則表明這個函數是內聯函數!因此當該函數較長時,應該將聲明和定義分開。

  可以通過指針或引用來返回多個值,因爲返回機制只能返回一個值,所以其它的返回值當做參數來傳入,通過引用或指針。如果按值傳遞時,對象很大,則系統開銷會很大(比如對象傳入和返回,要創建2次臨時對象,因此也會多次調用構造函數和析構函數),此時,一般採用按地址傳遞或按引用傳遞。

  既然引用實現了指針的功能,而且使用起來更加方便,爲什麼還要指針呢?

  這是因爲指針可以爲空,但是引用不能爲空,指針可以被賦值,但是引用只可以被初始化,不可以被賦爲另一個對象的別名。如果你想使用一個變量來記錄不同對象的地址,那麼就必須使用指針,另外指針也可以是多重的。

  指針可以指向堆中空間,引用不能指向堆中空間。但指針和引用可以一同使用,另外要注意引用的生命週期。

  對於引用而言,如果引用是一個臨時變量,那麼這個臨時變量的生存週期不會小於這個引用的生存期。指針不具備這個特性。

  爲了避免內存泄露,我們不能按值的方式返回一個堆中對象,而必須按地址或者別名的方式返回一個別名或者內存地址,這樣就不會調用複製構造函數來創建一個該對象的副本了,而是直接將該對象的別名或者地址返回。

  爲了避免指針混淆,我們必須對堆中的內存在哪個函數中創建,就在哪個函數中釋放。

  如果函數名相同,函數參數的個數也相同,只是參數的類型不同,則也可以是函數重載。

  如果函數有缺省值,則在調用時該參數可以不傳入,這樣相當於函數個數少了。

  默認參數其實也可以看做是一種函數重載,但默認參數的函數如果不加標註的話很容易被忽略,而且容易被有參數的同名函數覆蓋。而通常的重載函數使用方便,易於理解。具有默認參數的重載的是參數的數值,而重載函數重載的是參數的類型。

  我可以對構造函數的函數頭對常量和引用進行初始化,此時的初始化順序是按照成員列表的順序進行的,而不是按構造函數頭賦值的順序。而析構順序恰好相反。

  一般情況下,編譯器會自動爲類生成一個默認的複製構造函數。

  清楚構造函數和new的結合,析構函數和delete的結合。

  構造函數是不能設置爲私有的。

  默認的構造函數是淺層的構造函數,如果類中的成員變量有指針的話,就很有可能出現內存泄露的錯誤,因此此時需要使用深層的構造函數。

  用已有對象來創建對象時,纔會調用複製構造函數。如果複製符左側是已有對象,右側也是已有對象,則不會調用複製構造函數,而是調用一個賦值運算符函數。

  只要創建一個類,編譯器就會自動添加4個函數:構造函數,析構函數,複製構造函數,賦值運算符函數,其中系統默認的複製構造函數和複製運算符都屬於淺層拷貝。

  默認的自加重載運算符爲前置自加運算符。

  可以通過創建一個無名的臨時對象來完成重載自加後的對象賦值操作。當然了,較好的方法是返回*this指針,這樣就不需要建立一個臨時對象了,不過它依舊會調用賦值運算符,爲了避免這種情況,可以將重載自加函數返回值類型設爲返回對象的引用。

  重載後置自加運算符時,爲了區分與前置自加的區別,需要添加一個毫無意義的參數,這個參數只是在編譯器中使用到,在函數體中沒用。

  在一條語句中自加運算符的執行順序爲從右向左,且不同的編譯器入棧的順序不同,比如說VC6.0中其入棧是要求該語句的表達式執行完後。因此a=1;cout<<a++<<++a;則分別輸出的是2,2;

  ++的結合性爲右結合,所以++++i合法,而i++++不合法,可以改爲(i++)++;

  函數的按值返回時,會建立一個臨時的對象,返回完後隨後又被銷燬。

  在符合隱式類型轉換的情況下,可以將一個變量賦值給一個對象,但是不能反過來(除非自己重寫重載函數)。

  重載類型轉換運算符是沒有返回值的,和構造函數,析構函數一樣。

  只有派生類對象可以賦值給基類對象,反過來是不行的。另外,基類指針和引用可以指向派生類,反過來也是不行的。

  多重繼承允許分別設置基類的派生權限。

  單一繼承中構造與析構的順序時,先構造的對象後析構。如果是多重繼承,則構對象函數的順序按照繼承列表中的順序來。

  多重繼承中,如果多個基類中的函數名相同,則在子類對象調用該函數時會產生混淆,此時應該加入類作用域符。

  當我們在子類中定義一個與基類相同的同名函數時,那麼等於告訴編譯器,用子類的函數覆蓋掉基類的同名函數,同時將基類的重載函數給隱藏起來了,此時子類對象中不能再調用父類的對應的重載函數了。

  const對象只能調用const成員函數。

  如果一個派生類從多個基類派生,而這些基類又有一個共同的基類,那麼在派生類中訪問共同基類中的成員函數時會產生二義性,解決方法是需要指定類的作用域,或者將共同的基類設置爲虛基類,因爲虛基類不會產生二義性。

  一個虛函數被說明爲虛函數,在派生類中覆蓋了該函數,那麼該函數也是個虛函數,不過你也可以在它前面添加關鍵字virtual,這樣更容易理解。

  繼承所體現出的不同子類相同函數有不同的表現,但是這個並不能體現類的多態性,因爲類的多態性要求可以用基類指針來操作子類。

  將一個調用函數聯接上被正確調用的函數,這一過程叫做函數聯編,一般簡稱爲聯編,聯編分爲靜態聯編和動態聯編2種。

  需要分清楚在編譯時的靜態聯編,在運行時的靜態聯編,在編譯時的動態聯編,在運行時的動態聯編這幾種情況。

  假如我們在虛函數中沒有采用指針或引用,那麼就無法實現動態聯編。

  三種調用虛函數的方式,即按值調用,按指針調用和按引用調用,其中只有按值調用不能體現類的多態性,其它2種都可以。

  在虛函數中可以使用成員名限定強行解除動態聯編。

  如果基類中定義了虛函數,析構函數也應該說明爲虛函數。這樣對內存的回收會更準確些。基類是虛析構函數時,如果派生類被銷燬,則首先是調用派生類的析構函數,然後纔是基類的析構函數。

  數組通常比較大,所以爲了節省內存,C++規定數組在程序只有一個原本,由於這個原因,數組在函數中是不可能在創造一個副本的。C++爲了追求程序的運行速度,不對數組進行越界檢查。

  如果a表示的是數組指針,delete[] a,表示刪除堆中的指針數組a,而delete a,表示刪除堆中的指針數組第一個指針。

  用cin輸入字符時,會把空格當做是字符串的結束字符,因此可以採用gets()函數。或者使用cin.get()函數,該函數有2個參數,第一個是數組,第二個是字符串的大小。

  在重載下標運算符函數時應該注意:1.由於函數的參數即是數組的下標,因此該函數只能帶一個參數,不可帶多個參數。2.由於下標運算符只限於本類的對象使用,因此不得將下標運算符函數重載爲友元函數,且要求是非靜態類的成員函數。

  由於malloc和free函數產生於C語言時代,因此不可用在c++的對象中,因爲對象的產生要調用構造函數。

  dynamic_cast的作用是對不同類之間的數據類型進行轉換,它可以將一個基類的指針轉換成一個派生類的指針。dynamic_cast屬於RTTI(運行時信息),需要在工程設置中將其啓動。在程序中應該少用RTTI.

  如果使用指向基類的指針來指向派生類,那麼該指針不能直接調用派生類中多餘的成員函數(可以通過強制類型轉換),除非該函數在基類中聲明成了虛函數。

  由抽象類派生的類需要爲每一個純虛函數賦予具體功能。抽象類不能用來定義抽象類對象,但是卻可以定義一個指向抽象類的指針。

  一個抽象基類仍然可以派生出抽象類,只要該類沒有把純虛函數全部覆蓋掉。因爲派生出的抽象類,如果其子類沒有將它的純虛函數全部覆蓋掉,那麼該子類也屬於抽象類。

  在用單一繼承就可以實現的情況下,不要使用多重繼承。

  靜態成員變量需要有定義和聲明兩個階段。且定義必須在全局定義,靜態成員在沒有對象之前已經存在了。

  公有的靜態成員函數在程序中所有的函數都能夠訪問它,即包括那些非類的成員函數。而私有靜態變量只能被類的成員函數調用,但前提是你必須定義一個對象。

  靜態成員函數和靜態成員變量是一樣的,它們不單屬於一個對象,而是屬於整個類。靜態成員函數只能調用靜態成員變量,不能調用普通的成員變量。

  雖然可以通過對象來訪問靜態成員函數,但是最好是用類限定符來訪問它們。

  基類和派生類都可以共享靜態成員。

  類中任何成員函數都可以訪問靜態成員,但是靜態成員函數不能直接訪問非靜態成員,只能通過對象名訪問該對象的非靜態成員。因爲靜態成員函數是屬於整個類的,沒有特定指向某個對象的this指針。

  靜態成員函數不能被說明爲虛函數。

  函數名是指向函數的第一條指令的常量指針,這與數組名是指向數組中第一個元素的常量指針一樣。

  函數指針應該將函數名和前面的指針給括起來。

  使用函數指針可以減小一些重複的代碼,因爲函數指針名可以看作是函數名的代號,我們可以通過它來直接調用,函數指針經常會在條件或者判斷語句裏出現,以便於用戶選擇調用不同名字但又返回值類型和參數類型完全相同的函數。

  函數指針可以作爲函數的參數傳入。

  可以使用typedef來簡化函數指針的聲明,後面以分號結束,注意這點和宏定義是不同的,也可以在類中使用成員函數指針,或者成員函數指針數組。

  空格的ascii碼爲32,而空字符的ascii碼爲0.

  cout遇到空字符會停止輸出,但與cin不同的是,cout可以輸出空格,製表符等空字符或者不可見字符。

  如果char型數組後面沒有添加字符串結束符的話,這它不是一個字符串,而是一個數組。

  strlen返回的是字符串結束標誌’\o’之前的字符串長度,而不是數組長度。sizeof返回的是數組的所佔的字節長度。

  char字符串的比較只能用循環的方式進行(或者使用庫函數strcmp函數),而string的比較可以直接用等號。

  不可以直接對char型字符串數組進行賦值操作,而只能使用strcpy函數,或者對數組每個元素一個個的賦值。而string類的字符串可以直接用等號進行賦值。另外,string類中還有一個專門的賦值函數assign,這個函數可指定賦值字符串起點和長度。

  查看char型字符串的長度可以用strlen函數。string中用size成員函數實現該功能。當然了string類中的length函數也是一樣的功能,兩者的區別僅僅在size是爲了兼容STL而出現的,而length是早起的string計算長度的版本。

  未被初始化的string對象是個空對象,除了字符串結束標誌外,沒有任何數據。

  在char中,strncat可以實現部分字符串的合併。在string中是append函數。同理,char中用strncpy來實現字符串的替換,在string中使用replace來實現該功能,且replace的重載函數中可以兼容char型字符串數組。

  char型字符串的拷貝用memmove, string中使用copy成員函數。

  string中用insert來插入,其string類是從下標爲1開始數的。erase完成字符串的刪除。

  char型字符串的查找使用函數strchr。而string類中使用find函數實現。該函數有很多變形的函數,比如find_first_not_of函數,表示找到第一個不相同的字符。同理還有find_first_of,find_last_of等函數。反向查找使用rfind()函數,但是它的返回值位置還是從頭開始的,並不是從末尾開始的。

  string中用compare實現比較,它的c_str()返回一個指向char型的const指針。

char型字符串傳參數到函數中時(可以通過指針或者字符串數組傳入),可以不用傳入字符串的長度,因爲它有結束符,可以用來作爲其結束的標誌。

  C++中結構體與類唯一不同的區別是,結構體的成員默認的是公有的,其它類有的,結構體也有,比如繼承,多態等。

  爲了使計算機執行減法,採用了補碼的形式,因爲引入了負號。

  派生類的析構函數會自動調用基類的析構函數。

  只要基類中的析構函數被說明爲虛函數,那麼派生類的析構函數無論說明與否,都自然是虛構函數。

  友元函數並不是類的成員函數,而是類的外部函數,但是該外部函數中類的對象可以調用類的私有成員,而一般情況下,類的對象時不能調用類的私有成員的。

  常量對象只能調用可操作常量對象的成員函數(即參數括號後面帶有const的成員函數),而不是常量對象的成員函數只能被非常量對象調用,因此常量成員函數和非常量成員函數也算是一種函數重載形式。常量對象的私有數據成員是不能夠被修改的,除非在構造函數中第一次修改。且const成員函數中不能調用非const函數。

  友元類的作用不是相互的,需要單獨設置。

  包含對象是將另一個類的對象作爲該類的成員,而嵌套類是在該類中定義了一種新類型,這個類型只能在該類中使用。由於嵌套類作爲一種自定義的數據類型被封裝在另一個類中,因此可避免與其它類的名稱衝突

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章