c++學習**:
english:
中 文 :首頁
類名 物件名例如:clock myclock;
注意:物件佔據的記憶體只存放資料成員,每個函式在記憶體中只佔據乙份空間。
templateclass a;
template《模板形參列表》
函式返回型別 類名《模板形參名》::函式名(引數列表),
比如有兩個模板形參t1,t2的類a中含有乙個voidh()函式,則定義該函式的語法為:
templatevoid a::h()
比如乙個模板類a,則使用類模板建立物件的方法為a< int > m;
派生類不繼承基類的建構函式與析構函式。基類的public和protected 的訪問屬性在派生類中不變,而基類的private不可訪問
基類的public和protected的訪問屬性在派生類中變成private屬性,而基類的private不可訪問
基類的public和protected的訪問屬性在派生類中變成rotected屬性,而基類的private不可訪問(protected可以被派生類訪問,但不能被物件訪問)
通過以下方式呼叫基類函式(適用於繼承多個基類,與多型正相反):基類 p=派生類
p.fun();
或 基類 *p=派生類
p->fun();
class base1;
int main ()
class base2:virtual public base0
derived.val=2;
derived.fun();
多型與非多型的實質區別就是函式位址是早繫結還是晚繫結。如果函式的呼叫,在編譯器編譯期間就可以確定函式的呼叫位址,並生產**,是靜態的,就是說位址是早繫結的。而如果函式呼叫的位址不能在編譯器期間確定,需要在執行時才確定,這就屬於晚繫結。
那麼多型的作用是什麼呢,封裝可以使得**模組化,繼承可以擴充套件已存在的**,他們的目的都是為了**重用。而多型的目的則是為了介面重用。也就是說,不論傳遞過來的究竟是那個類的物件,函式都能夠通過同乙個介面呼叫到適應各自物件的實現方法。
基類 virtual void display();派生類1 void display();
派生類2 void display();
base *p=派生類x
p->display();//顯示方式根據派生類x而定
例項:virtual void display() = 0;
基本語法如下
[capture](parameters) mutable ->return-type
各部分解釋如下
1.[capture]:捕捉列表。捕捉列表總是出現在lambda函式的開始處。實際上,是lambda引出符。編譯器根據該引出符判斷接下來的**是否是lambda函式。捕捉列表能夠捕捉上下文中的變數以供lambda函式使用;
2.(parameters):引數列表。與普通函式的引數列表一致。如果不需要引數傳遞,則可以連同括號「()」一起省略;
3.mutable:mutable修飾符。預設情況下,lambda函式總是乙個const函式,mutable可以取消其常量性。在使用該修飾符時,引數列表不可省略(即使引數為空);
4.->return-type:返回型別。用追蹤返回型別形式宣告函式的返回型別。我們可以在不需要返回值的時候也可以連同符號->一起省略。此外,在返回型別明確的情況下,也可以省略該部分,讓編譯器對返回型別進行推導;
5.:函式體。內容與普通函式一樣,不過除了可以使用引數之外,還可以使用所有捕獲的變數。
注意到,lamda表示式,與普通函式,最大的不同,在於擁有捕獲列表。捕獲列表有一下幾種形式
[var]表示值傳遞方式捕捉變數var;
[=]表示值傳遞方式捕捉所有父作用域的變數(包括this);
[&var]表示引用傳遞捕捉變數var;
[&]表示引用傳遞方式捕捉所有父作用域的變數(包括this);
[this]表示值傳遞方式捕捉當前的this指標。
注意的是,捕獲列表可以組合,但是不能重複。
// 合法的例子:
[&, a, b]
[=, &a, &b]
// 非法的例子:
[=, a]
[&, &a]
lamda的使用
用於函式引數
在使用stl時,我們有時需要傳遞一些函式引數給stl的演算法函式,在沒有lamda表示式之前,我們有兩種做法,一種是傳遞函式,一種是傳遞函式物件。現在,我們可以簡單的傳遞lamda表示式,比如:
for_each(vec.begin(), vec.end(), (int v))
當出現類的等號賦值時,會呼叫拷貝函式,在未定義顯示拷貝建構函式的情況下,系統會呼叫預設的拷貝函式——即淺拷貝,它能夠完成成員的一一複製。當資料成員中沒有指標時,淺拷貝是可行的。
但當資料成員中有指標時 ,如果採用簡單的淺拷貝,則兩類中的兩個指標將指向同乙個位址,當物件快結束時,會呼叫兩次析構函式,而導致指標懸掛現象。所以,這時,必須採用深拷貝。
深拷貝與淺拷貝的區別就在於深拷貝會在堆記憶體中另外申請空間來儲存資料,從而也就解決了指標懸掛的問題。指向不同的記憶體空間,但內容是一樣的
簡而言之,當資料成員中有指標時,必須要用深拷貝。
這裡再總結一下深複製和淺複製的具體區別:
當拷貝物件狀態中包含其他物件的引用時,如果需要複製的是引用物件指向的內容,而不是引用記憶體位址,則是深複製,否則是淺複製。
淺複製就是成員資料之間的賦值,當值拷貝時,兩個物件就有共同的資源。而深拷貝是先將資源複製乙份,是物件擁有不同的資源(記憶體區域),但資源內容(記憶體裡面的資料)是相同的。
與淺複製不同,深複製在處理引用時,如果改變新物件內容將不會影響到原物件內容
與深複製不同,淺複製資源後釋放資源時可能會產生資源歸屬不清楚的情況(含指標時,釋放一方的資源,其實另一方的資源也隨之釋放了),從而導致程式執行出錯
深複製和淺複製還有個區別就是執行的時候,淺複製是直接複製記憶體位址的,而深複製需要重新開闢同樣大小的記憶體區域,然後複製整個資源。
有了前面的鋪墊,下面開始講講拷貝建構函式和賦值函式,其實前面第一部分也已經介紹了許多
這裡以string 類為例來進行說明。
class string
private:
char *m_data;
};//建構函式
string::string(const char* str)
else
}//拷貝建構函式,無需檢驗引數的有效性
string::string(const string &rhs)
//賦值函式
string& string::operator=(const string &rhs)
類string 拷貝建構函式與普通建構函式的區別是:在函式入口處無需與 null 進行比較,這是因為「引用」不可能是null,而「指標」可以為null。(這是引用與指標的乙個重要區別)。然後需要注意的就是深複製了。
相比而言,對於類string 的賦值函式則要複雜的多:
1、首先需要執行檢查自賦值
這是防止自複製以及間接複製,如 b = a; c = b; a = c;之類,如果不進行自檢的話,那麼後面的 delete 將會進行自殺操作,後面隨之的拷貝操作也會出錯,所以這是關鍵的一步。還需要注意的是,自檢是檢查位址,而不是內容,記憶體位址是唯一的。必須是 if(this == &rhs)
2、釋放原有的記憶體資源
必須要用 delete 釋放掉原有的記憶體資源,如果此時不釋放,該變數指向的記憶體位址將不再是原有記憶體位址,也就無法進行記憶體釋放,造成記憶體洩露。
3、分配新的記憶體資源,並複製資源
這樣變數指向的記憶體位址變了,但是裡面的資源是一樣的
4、返回本物件的引用
這樣的目的是為了實現像 a = b = c; 這樣的鏈式表達,注意返回的是 *this 。
C 基礎知識
抽象類 abstract class 一種不可以被例項化的類。抽象類中一般含有抽象方法,當然也可有具體實現。繼承類只有實現過所有抽象類的抽象方法後才能被例項化。介面 inte ce 只含有共有抽象方法 public abstract method 的類。這些方法必須在子類中被實現。反射 程式集包含模...
c 基礎知識
或運算的意義是什麼 0 0 0 0 1 1 1 0 1 1 1 1 無進製與運算的意義是什麼 在vc中,視窗的每個屬性對應乙個只有一位為1的16位的二進位制數,當增加某屬性做或運算 即可,取消某個屬性只需與 上這個屬性的取反。cs.style ws maximizebox 和cs.style cs....
C 基礎知識
1 malloc和new區別與聯絡 a malloc malloc為函式,需要標頭檔案,申請的無型別,需要強制轉換 free釋放。示例 char p char malloc 10 sizeof char free p b new new是運算子,不需要標頭檔案,申請的是有型別的,自動呼叫建構函式 d...