1. 程式人生 > >C++零散知識

C++零散知識

1、volatile關鍵字:
提醒編譯器它後面所定義的變數隨時都有可能改變,因此編譯後的程式每次需要儲存或讀取這個變數的時候,都會直接從變數地址中讀取資料。如果沒有volatile關鍵字,則編譯器可能優化讀取和儲存,可能暫時使用暫存器中的值,如果這個變數由別的程式更新了的話,將出現不一致的現象。

2、new關鍵字:
new 關鍵字建立物件時,對於內建型別:加括號會初始化,不加括號不初始化;對於自定義型別,都會呼叫預設建構函式,加不加括號沒區別。

3、C++ 的Virtual的用法:
(1)虛擬函式:類Base中加了Virtual關鍵字的函式就是虛擬函式(例如函式print),於是在Base的派生類Derived中就可以通過重寫虛擬函式來實現對基類虛擬函式的覆蓋。當基類Base的指標point指向派生類Derived的物件時,對point的print函式的呼叫實際上是呼叫了Derived的print函式而不是Base的print函式。這是面向物件中的多型性的體現。
注意:基類的函式呼叫如果有virtual則根據多型性呼叫派生類的,如果沒有virtual則是正常的靜態函式呼叫,還是呼叫基類的。
(2)純虛擬函式:C++語言為我們提供了一種語法結構,通過它可以指明,一個虛擬函式只是提供了一個可被子型別改寫的介面。但是,它本身並不能通過虛擬機制被呼叫。這就是純虛擬函式(purevirtual function)。
注意:包含一個或多個純虛擬函式的類被編譯器識別為抽象基類。抽象基類不能被例項化,一般用於繼承。
(3)虛擬繼承(virtual public):在多繼承下,虛繼承就是為了解決菱形繼承中,B,C都繼承了A,D繼承了B,C,那麼D關於A的引用只有一次,而不是普通繼承的對於A引用了兩次。格式:可以採用public、protected、private三種不同的繼承關鍵字進行修飾,只要確保包含virtual就可以了。
虛繼承:在繼承定義中包含了virtual關鍵字的繼承關係;
虛基類:在虛繼承體系中的通過virtual繼承而來的基類。
注意:C++標準中(也是很自然的)選擇在每一次繼承子類中都必須書寫初始化語句(因為每一次繼承子類可能都會用來定義物件),而在最下層繼承子類中實際執行初始化過程。所以上面在每一個繼承類中都要書寫初始化語句,但是在建立物件時,而僅 僅會在建立物件用的類建構函式中實際的執行初始化語句,其他的初始化語句都會被壓制不呼叫。

4、 static 關鍵字的用途:
C 語言的 static 關鍵字有三種(具體來說是兩種)用途:

  1. 靜態區域性變數:用於函式體內部修飾變數,這種變數的生存期長於該函式。對於一個完整的程式,在記憶體中的分佈情況如下圖: 
    (1)棧區: 由編譯器自動分配釋放,像區域性變數,函式引數,都是在棧區。會隨著作用於退出而釋放空間。
    (2)堆區:程式設計師分配並釋放的區域,像malloc©,new(c++) 。
    (3)全域性資料區(靜態區):全域性變數和靜態便令的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。程式結束釋放。
    (4)程式碼區。
    note:1的static是在全域性資料區分配的:它存在的意義就是隨著第一次函式的呼叫而初始化,卻不隨著函式的呼叫結束而銷燬。那麼第二個問題也就浮出水面了,它是在第一次呼叫函式的時候初始化。且只初始化一次,也就是你第二次呼叫函式,不會繼續初始化,而會直接跳過。
    那麼它跟定義一個全域性變數有什麼區別呢,同樣是初始化一次,連續呼叫函式的結果是一樣的,但是,使用全域性變數的話,變數就不屬於函式本身了,不再僅受函式的控制,給程式的維護帶來不便。靜態區域性變數正好可以解決這個問題。靜態區域性變數儲存在全域性資料區,而不是儲存在棧中,每次的值保持到下一次呼叫,直到下次賦新值。
    總結:
    (1)該變數在全域性資料區分配記憶體(區域性變數在棧區分配記憶體);
    (2)靜態區域性變數在程式執行到該物件的宣告處時被首次初始化,即以後的函式呼叫不再進行初始化(區域性變數每次函式呼叫都會被初始化);
    (3)靜態區域性變數一般在宣告處初始化,如果沒有顯式初始化,會被程式自動初始化為0(區域性變數不會被初始化);
    (4)它始終駐留在全域性資料區,直到程式執行結束。但其作用域為區域性作用域,也就是不能在函式體外面使用它(區域性變數在棧區,在函式結束後立即釋放記憶體);
    2.靜態全域性變數:定義在函式體外,用於修飾全域性變數,表示該變數只在本檔案可見:
    靜態全域性變數不能被其它檔案所用(全域性變數可以);
    其它檔案中可以定義相同名字的變數,不會發生衝突(自然了,因為static隔離了檔案,其它檔案使用相同的名字的變數,也跟它沒關係了);
    3.靜態函式:準確的說,靜態函式跟靜態全域性變數的作用類似。所以,靜態函式的好處跟靜態全域性變數的好處就類似了:
    1.靜態函式不能被其它檔案所用;
    2.其它檔案中可以定義相同名字的函式,不會發生衝突;

C++ 語言的 static 關鍵字有二種用途:
當然以上的幾種,也可以用在c++中。還有額外的兩種用法:
1.靜態資料成員:用於修飾 class 的資料成員,即所謂“靜態成員”。這種資料成員的生存期大於 class 的物件(實體 instance)。靜態資料成員是每個class 有一份,普通資料成員是每個 instance 有一份,因此靜態資料成員也叫做類變數,而普通資料成員也叫做例項變數。
2、靜態成員函式:用於修飾 class 的成員函式。那麼靜態成員函式有特點呢?
(1)靜態成員之間可以相互訪問,包括靜態成員函式訪問靜態資料成員和訪問靜態成員函式;
(2)非靜態成員函式可以任意地訪問靜態成員函式和靜態資料成員;
(3)靜態成員函式不能訪問非靜態成員函式和非靜態資料成員;
(4)呼叫靜態成員函式,可以用成員訪問操作符(.)和(->)為一個類的物件或指向類物件的指標呼叫靜態成員函式,也可以用類名::函式名呼叫(因為他本來就是屬於類的,用類名呼叫很正常)。
重點

:靜態成員函式訪問非靜態成員方法:
1、有一個很取巧的辦法,就是在靜態函式的形參表裡加上例項的地址,也就是
class A
{
public:
static void test(A *a)
{
a->m_a += 1;
}
void hello()
{
}
private:
static int m_staticA;
int m_a
};
這樣在你回撥函式的時候,你可以通過這個來讓本身不能訪問成員非靜態變數的靜態函式(太拗口)來訪問非靜態成員變數。
2、大家都知道靜態成員函式不能訪問非靜態成員,但別忘了,他們可以訪問靜態成員,也就是說,如果我們的這個類是個單例,我們完全可以在建立的時候把this指標賦值給那個靜態成員,然後在靜態成員函式內部就可以放心大膽的使用了。
class A
{
public:
A()
{
m_gA = this;
}
static void test()
{
m_gA.m_a += 1;
}
void hello()
{
}
private:
static int m_staticA;
static A *m_gA;
int m_a
};
3、和方法一比較像,但他的方向思想更多的是針對記憶體塊這個概念,意思就是在靜態函式的形參比加上一個void *的記憶體首地址,然後在內部做轉換
class A
{
public:
static void test(void *pData)
{
A *a = (A *)pData;
a->m_a += 1;
}
void hello()
{
}
private:
static int m_staticA;
int m_a
};
A a;
test(&a);

5、default”標籤跳過“ ”的初始化操作問題:
原因是在switch 中有初始化的工作。在switch 語句中不可以有定義部分。如果有定義,如初始化的時候,必須把定義部分需要用{ } 括起來。

6、static和const的作用:
static的作用:
1). 靜態區域性變數:用於函式體內部修飾變數,這種變數的生存期長於該函式。
2).靜態全域性變數:定義在函式體外,用於修飾全域性變數,表示該變數只在本檔案可見。
3).靜態函式:準確的說,靜態函式跟靜態全域性變數的作用類似,所以,靜態函式的好處跟靜態全域性變數的好處就類似了。
4).靜態資料成員:用於修飾 class 的資料成員,即所謂“靜態成員”。這種資料成員的生存期大於 class 的物件(實體 instance)。靜態資料成員是每個class 有一份,普通資料成員是每個 instance 有一份,因此靜態資料成員也叫做類變數,而普通資料成員也叫做例項變數。
5).靜態成員函式:用於修飾 class 的成員函式。

const的作用:
1、定義常量,使變數不可被改變,注意需先初始化。
2、定義指標本身為常量,定義指標所指向的內容不可改變。
3、在函式中可修飾形參,使其在函式內部不可改變。

7、指標和引用的區別:
1).指標:指標是一個變數,只不過這個變數儲存的是一個地址,指向記憶體的一個儲存單元;而引用跟原來的變數實質上是同一個東西,只不過是原變數的一個別名而已。
2).引用不可以為空,當被建立的時候,必須初始化,而指標可以是空值,可以在任何時候被初始化。
3).可以有const指標,但是沒有const引用。
4).指標可以有多級,但是引用只能是一級。
5).指標的值在初始化後可以改變,即指向其它的儲存單元,而引用在進行初始化後就不會再改變了。
6).”sizeof引用”得到的是所指向的變數(物件)的大小,而”sizeof指標”得到的是指標本身的大小。
7).指標和引用的自增(++)運算意義不一樣。
8).程式為指標變數分配記憶體區域,而引用不需要分配記憶體區域。
9).指標和引用作為函式引數進行傳遞時也不同。用指標傳遞引數,可以實現對實參進行改變的目的;在將引用作為函式引數進行傳遞時,實質上傳遞的是實參本身,而不是實參的一個拷貝,因此對形參的修改其實是對實參的修改。