【C++】C++進階

1.C++介紹:
C語言作爲結構化和模塊化語言適合規模較小的程序,對於大規模的複雜程序,能夠高度抽象和建模的C++則更加適合,C++是C語言的加強版,以C語言爲基礎,並且完全兼容C語言的特性。
在這裏插入圖片描述
2.C++對C語言的增強語法
2.1.命名空間
2.2.引用
2.3.函數與運算符的重載
2.4.面向對象的特性
2.5.泛型編程
2.6.異常處理
2.7.標準模板庫
下面筆者就者7個特性進行詳細說明:
3.命名空間
命名空間是C++提供的一種解決不同文件互相調用時符號名字衝突的方法,一個命名空間就是一個作用域,在不同的命名空間下允許相同的名字符號代表不同的實體。
3.1命名空間的定義
在這裏插入圖片描述
注意:命名空間的聲明要在類和函數的外面定義,並且沒有分號結束。
3.2.命名空間成員的引用
命名空間名::成員名
如:
1.cpp
#include
using namesapce std;
/*
命名空間的聲明方式,我們需要用到命名空間中的什麼方法就在{}內加入什麼方法的聲明,當然直接使用“using namespace A”來聲明A命名空間也是可以的,但是這種命名方法會將A命名空間下的所有方法都作聲明,包括我們可能沒有使用的方法,當工程很大時,這種做法會導致代碼臃腫。
/
namespace A {
int add(int a,int b);
}
int add(int a,int b);
int mian(){
int a = 1,b = 1;
/

在很多多人編程的時候,如果各程序員之間不一直進行密切的交流,極容易出現變量名或方法名類名等相同的情況,這樣 在;多文檔聯合編譯時,編譯器會無法區分同名符號而報錯,而命名空間就很好的解決了這種問題,我們爲各個文檔都定義一個唯一的命名空間,這樣即使是相同符號也可以通過命名空間唯一標識了,命名空間的出現極大的改善了多人編程的困處
/
cout << add(a,b)<<" "<<A::add(a,b)<< endl;
return 0;
}
int add(int a,int b){
return(a + b);
}
2.cpp
#include
namespace A {
int add(int a,int b){
return(a + b);
}
}
3.3.命名空間的別名
命名空間是可以另起別命的,別命是已定義的命名空間的可代替的名字,一個命名空間可以有很多個別名,所有的別命和命名空間原名可以互換使用
別命的定義:namespace 別命 = 命名空間原名;
在這裏插入圖片描述
3.4.命名空間的成員類型
命名空間的成員類型可以是變量、常量、函數、結構體、聯合體、枚舉、類、嵌套的命名空間
3.5.全局命名空間
在全局作用域中定義的命名空間,大多數命名空間都屬於全局命名空間。即自定義的命名空間是全局命名空間的擴張和細分。全局命名空間是隱式聲明的,它存在於每一個程序中。
由於全局命名空間是隱含的,它沒有名字,所以使用“::成員名字”引用全局命名空間。
3.6.匿名命名空間
匿名命名空間與全局命名空間類似,也沒有名字,但是匿名命名空間定義在局部作用域,不能用於多文件編譯。
匿名命名空間可以直接使用變量名引用成員。
4.引用
4.1.什麼是引用?
引用即別命,是某一個變量或對象的別命,綁定一個引用到一個變量或對象,即引用初始化,之後對引用的操作完全等價於對與其綁定的變量或對象的操作。
4.2.引用的定義
類型 &引用名 = 目標變量名;
需要注意的是:
- &不是求地址運算符,而是起標誌作用
- 引用的類型必須和其所綁定的變量類型相同
- 聲明應用的同時必須對其初始化,否則系統會報錯
- 引用相當於變量或對象的別命,因此不可將已綁定的引用再綁定其他變量或對象,也不可將一個引用綁定另一個引用。
4.3.引用與指針的區別
+佔用存儲空間上:
-引用佔用一個地址空間,本地計算機的一個地址空間是多少位,引用就佔多少位的地址空間。
-而指針除了佔用一個地址空間外,還佔用一個數據空間用於存儲其指向的變量或對象的地址。
+在操作上:
-引用聲明的同時必須對其初始化,且初始化後引用不可更改,引用不能爲空。如:int &a ;是錯誤的用法,正確的用法應該是:int &a = b;
-指針的聲明可以在任何時候初始化,且指針在後續操作中可以變更其指向的變量或對象,指針可以爲空。
+存儲內容上
-“sizeof引用”得到的是引用所指向的變量或對象的大小
-“sizeof指針”得到的是指針本身的大小
+層級上
-引用只能有一級,引用不可以再指向引用
-指針理論上對級數沒有限制
+可以將引用理解爲不可更改的指針,即:類型
const 指針變量
4.4.對數組的引用
類型 (&引用名)[數組下標] = 數組名;
如:對int a[3]數組的引用爲int (&quote)[3] = a;即將引用名替換成數組名。
這裏要注意,“()”是不能省略的,因爲如果省略(),則會改變優先級,變成int &(quote[3]) = a;而出現語法錯誤。
4.5.對指針的引用
類型* &引用名 = 指針名;
如:int* &quote = p;
4.6.引用的作用
引用既可以作爲別命使用,還可以作爲函數的參數、函數的返回值使用。
需要注意的是,引用作爲函數的返回值時不能返回局部變量的引用。
至此,我可能提出這樣的疑問:引用能做的事指針也能做,引用不能做的事指針還能做,那麼C++麼什麼要引入“引用”這個概念呢?
這是因爲,指針的操作太過於強大,正因如此對指針的使用存在一定的風險,所謂“收益與風險並存”,在很多高版本的編譯器中已經不能再操作指針了,如VS2015,而C++之所以還保留着指針,是因爲指針的魅力無比誘人,儘管有風險卻不願意就此拋棄。
引用的另一個用處我們舉一個例子來說明
如:
int add_1(int b){
b++;
}
int add_2(int &c){
c++;
}
void mian(){
int a = 1;
int &a = a;
cout<<add_1(a)<<endl;
cout<<add_2(&a)<<endl;
}
我們的輸出結果是:1 2,爲什麼呢?因爲普通的參數傳遞,傳遞的是參數的拷貝,如add_1我們對b++,實際進行運算的是形參b,而實參a卻沒有發生運算,所以cout<<add_1(a)輸出1,而如果傳遞引用的話,我們在函數add_2中對引用的操作實質上就是對a進行運算,因爲&a就是a。
4.7.常引用
const 類型 &引用名 = 目標變量名
常引用可以引用常量也可以引用變量,常引用不允許通過引用對其綁定的變量或對象進行修改。
在這裏插入圖片描述5.函數重載
5.1.C++重載的實現
從本質上來說,C++之所以能實現函數的重載是因爲C++編譯器對函數名的處理方法進行了優化,我們來對比一下C語言編譯器和C++編譯器對函數名的編譯
+C語言編譯器
對函數 int add(int a);編譯後的名字爲:add
+C++編譯器
對函數int add(int a);編譯後的名字爲:addi,對int add(int a,float b);編譯後的名字爲:addij,C++編譯器使用函數名和參數類型的共同組合成編譯後函數的唯一標識,即可實現函數的重載。
5.2.重載的定義
重載就是在相同的聲明域中函數名相同而參數列表不同,通過函數的參數表唯一標識的函數。
5.3.函數的默認參數
C++可以使用默認參數,即在函數聲明時爲參數提供一個默認值,當函數調用時沒有指定這個參數的值時,編譯器會自動使用默認值替換。
在這裏插入圖片描述
需要注意的是,默認參數只能放在聲明或定義處,能放在聲明處就放在聲明處。如果某個參數是默認參數,那麼其後的參數也必須都是默認參數,如:int add(int a = 1,int b,int c);編譯器將報錯,而int add(int a,int b = 1,int c = 2);則不會報錯,因爲參數在傳遞的時候是從左到右的,首先使用無默認參數的參數列表,當遇到沒有傳入實參的形參時開始使用默認參數的參數列表。使用默認參數的情況僅限於用在沒有沒有重載衝突的函數上,如:重載add函數,int add(){…} int add(int a = 1,int b = 2){…},此時調用add();將調用不帶參數的add()函數。
在這裏插入圖片描述5.4.內聯函數
5.4.1.爲什麼需要內聯函數?
在程序執行的過程中,當碰到函數調用時,系統要將程序當前狀態保存到棧中,同時跳轉到函數代碼處執行函數體,此過程需要佔用時間和空間,是的程序執行效率低下。當然我們聲明一個內聯函數只是建議編譯器將此函數作爲內聯函數,但是編譯器有自己的判斷算法,在編譯時編譯器會自行判斷我們聲明的內聯函數是否值得變爲內聯函數,以保證主程序體不會過於臃腫,所以我們聲明的內聯函數不一定會成爲內聯函數。
5.4.2.內聯函數的定義
inline 返回值類型 函數名(參數列表){函數體;}
5.4.3.內聯函數是一種用空間換時間的措施,通常只有較短的函數才定義爲內聯函數。
6.new和delete運算符
6.1.new運算符的功能是在堆區分配內存,通過new運算符獲得的內存空間都處於堆上。delete運算符的功能正好與new相反,delete運算符的功能是釋放new運算符的在堆區創建的內存,new運算符與delete運算符最好是配套出現,即使用new運算符創建了內存就一定要用delete運算符在不需要的時候此內存的時候將其釋放,爲什麼呢?因爲堆區的內存是不會隨着程序結束而釋放的,堆區的內存只要在操作系統關閉時纔會釋放,所以如果不手動釋放new運算符在堆區創建的內存,則會造成大量無用數據佔據着堆區內存,當堆區內存被佔滿時這會出現系統無堆區內存可用而出現系統死機。
6.2.new/delete運算符的使用
new <數據類型> (參數)
delete <對象指針>/delete <對象數組指針>
在這裏插入圖片描述
6.3.那麼C++的new/delete與C語言的malloc/free有什麼區別呢?
-它們都是動態管理內存的入口
-malloc/free是C/C++標準庫函數,而new/delete是C++操作符
-malloc/free只是動態分分配/釋放內存空間,而new/delete除了分配內存空間還會調用構造/析構函數進行初始化/清理(清理成員)
-malloc/free需要手動計算類型大小且返回值爲void,而new/delete可以自行計算類型大小返回對應類型的指針
-new/delete在底層是調用了malloc/free的。可以認爲是C++對malloc/free的封裝
-malloc/free申請空間後需要判空,new/delete則不需要
-new直接跟類型,malloc跟字節數。
new/delete和malloc/free的區別是C++企業招聘時特別喜歡考的一項
7.程序的內存空間
7.1.指針的內存操作
-指針不僅可以可以指向變量還可以指向函數
-有new運算符在堆區創建的內存空間由位於棧區的指針確定入口
在這裏插入圖片描述
說到這,我們有必要了解一下計算機程序的內存結構,供程序運行的內存空間分爲:堆區、棧區、.data段、.bss段、.ro段、.txt段,我使用一張圖來說明
在這裏插入圖片描述
8.面向對象編程的特點
在這裏插入圖片描述
9.C++中的類
9.1.類的定義
在這裏插入圖片描述
9.2.訪問權限
C++爲類的成員添加了三種訪問權限
-public–公有成員:權限最高,在public修飾下的成員是類的外部接口,可以被類的成員函數和對象直接訪問。
-protected–保護成員:權限居中,可以被類的成員函數和其派生類的成員函數直接訪問,但不能被類的對象和派生類的對象直接訪問。
-private–私有成員:權限最低,只能通過類的成員函數訪問。
9.3.類的成員
-成員變量:類的成員變量用以描述一個對象的屬性信息,與一般的變量聲明相同,但類的成員變量只能在類的聲明體中定義,類的成員變量一般在類的構造函數中初始化,但這不是必須的。
-成員函數:用來描述一個對象的行爲動作,與一般的函數聲明相同,但只能放在類的聲明體中聲明,成員函數可以在類內實現也可以在類外實現,但在類內實現則形成內聯的成員函數,會使類變得冗雜,所以成員函數的實現最好在類外實現,類成員函數可以重載和帶默認參數。
9.5.類的成員函數與成員變量的聲明與實現
在這裏插入圖片描述
9.6.struct和class的區別
-C++對struct關鍵字擴展了其功能,和class的功能幾乎等價
-struct的成員默認訪問權限是public,而class是private
9.7.this指針
-this指針是一個特殊的指針,指向對象的自身的首地址
-每一個對象的成員函數都有一個this指針,指向調用的對象,如果要引用整個對象則通過*this引用
-this指針僅能在類的內部使用,即只能在類的聲明體或成員函數中使用
9.8.static關鍵字
9.8.1.static修飾的成員變量–靜態成員變量
-static修飾的變量存儲在靜態變量區
-在類中static關鍵字修飾的變量被此類的所有對象共享,即所有對象共享這一個變量
-static修飾的變量必須在類外初始化,不可以在定義的時候直接初始化
-static修飾的公有成員變量可以直接通過類名來訪問,沒有staic修飾的成員變量只能通過對象才能訪問
在這裏插入圖片描述
9.8.2.static修飾的成員函數–靜態成員函數
-static修飾的成員函數也可以直接通過類名訪問
-靜態成員函數只能訪問靜態成員變量
9.8.3.類的靜態與非靜態部分
-靜態部分只屬於類,與類一起存放在內存的靜態區,被所有對象共享
-非靜態部分屬於對象,每個對象都有自己的非靜態部分,互不影響
-靜態部分只能直接訪問靜態部分,非靜態部分可以訪問所有部分
那麼爲什麼靜態部分只能直接訪問靜態部分,而非靜態部分卻可以訪問所有部分呢?
那是因爲,非靜態成員變量/函數是屬於對象的,只能通過對象來訪問,而靜態部分是屬於類的,使用靜態部分時沒有確定對象的存在,所以不能確定靜態部分應該訪問哪個對象的非靜態部分,而靜態部分是屬於類的,所有對象共享,所以通過對象使用非靜態部分時,可以訪問靜態部分。
思導圖:
在這裏插入圖片描述
在這裏插入圖片描述

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