c++面向對象

一·常量表達式和constexpr與const

常量表達式概念:值不會改變並且在編譯過程中就能計算出結果的表達式。

ps:constexpr int a=20;
constexpr int b=20+a;

constexpr必須用常量表達式初始化,也就是說必須在編譯過程就能計算出結果(若要用函數作爲constexpr的初始值那麼該函數應該是constexpr類型的函數)。

constexpr函數必須滿足下述限制:
函數返回值不能是void類型 函數體不能聲明變量或定義新的類型
函數體只能包含聲明、null語句或者一條return語句
在形參實參結合後,return語句中的表達式爲常量表達式

const 不要求在編譯過程中就能計算出結果 (強調運行時不可改變) 大多數情況下並沒有區別。

const限定指針和引用。

指向const對象的指針 const type 指針

const int a=1;  //const地址無法賦給非const指針所以應該定義一個指向const的指針
const int * b=&a;     //指向常量的指針,而非常指針。
const int c=2;
b=&c;   //指向對象可以改變,指向對象內容不能改變。
int d=10;
b=&d;  //也可以將一個非const地址賦給 指向const的指針 但是不能通過該指針改變該變量的內容。
*b=15;//錯誤

指向非const對象地const指針(常指針 ) type const 指針

   int num =10;
   int * const  poi =#// type const 指針 指針的值初始化後不能改變指向固定的單元(只能指一次)
   *poi=99;//const限定的是poi的值;可以對指向內容修改,但不可以對指針指向對象修改。
   int member=10;
   poi=&member;//錯誤

指向const對象的const指針

/*const type const 指針(第一個const限定int表示指針指向的單元是常量,
第二個const限定‘指針’表示指針的值也是常量,因此該指針所在的內存值不允許改變它所指向內存的值也不能改變)*/
int demo=10;
const int *const pi=&demo;對象及內容都不能改變

const限定引用,與const指針相似

const int a=1;
int 7b=a;// const type &引用名(不能用非const引用指向const對象)
const int& b=a;//right
b=10;//錯誤,const引用不能用來修改他所綁定的對象。
a=10;//const引用僅對自己可參與的操作進行了限定對所指向的對象本身是不是常量未作限定。因爲指向的對象也可能不是const,所以允許通過其他途徑改變它的值。
const int &c=a*10;//可以用任意表達式初始化const引用,只要表達式的結果能轉換成引用的類型即可。

二.auto和decltype

由auto聲明變量的類型由編譯器去自動分析表達式的類型,推斷出變量的實際類型(很好用)

auto x=5
auto x=1,c=3.14;//一個int 一個double錯!當auto後定義多個變量時類型要一致
auto poi=Set.begin()//很好用,省了set<type>::iterator 

decltype 可以通過表達式推斷出定義的變量的類型但是不用該表達式初始化。

int i = 4;
decltype(i) a; //推導結果爲int。a的類型爲int。

三.new和delete

new在對上動態分配空間創建對象並返回對象的地址,一般將返回的地址保存在指針變量中,以便間接訪問對上的對象

int *pi=new int;
int *poi=new int(1000);
 /*   new表達式的形式
1.分配單個對象new 類型,new 類型(初始值)
2.分配多個連續存儲的對象 new 類型[數組大小]
3.定位new(將對象創建在已經分配好的內存中) new (指針) 類型;*/

堆上的空間在使用後必須釋放否則會造成內存泄漏,

delete  pi;
delete poi[];

/*new分配的空間用delete運算符釋放。
1釋放 new分配的單個對象 delete 指針;
2釋放new分配的數組形式 delet[] 指針;
3 定位new沒有對應的形式;*/

執行delete運算後指針指向的空間被釋放歸還給自由空間不能再使用指針所指向的內容,但是指針自己的儲存空間還是存在的。該指針被稱爲空懸指針指向不確定的單元如果在繼續使用該指針間接使用這個單元就是非法的對自由空間造成損害進而引起不可預料的錯誤。

四.引用

左值與右值

區別 左值 右值
賦值表達式 出現在賦值號左邊 在賦值號右邊的
地址與名字 可以取地址的有名字 不能取地址的沒有名字
生成的表達式 返回左值引用的函數 賦值 下標 解引用和前綴自增自減運算符 返回非引用類型的函數 連同算術、關係、位運算、後綴自增自減運算符、字面值常量、要求轉換的表達式。

左值引用 (定義 類型 &引用名=目標變量名)

int a=100;
int &b=a;/*&是標識符(引用必須被初始化並且初始化完成之後引用將會和初始值對象一直綁定在一起)。*/
b=10;//又稱別名,它可以作爲對象的另一個名字,通過引用可以間接的操縱對象,對引用的操作和對對象的直接操作一樣。
int *poi=&a;
int *pi=&b;//此時a==b
/* 聲明一個引用,不是新定義了一個變量,它只表示該引用名是目標變量名的一個別名,它本身不是一種數據類型,因此引用本身不佔存儲單元,系統也不給引用分配存儲單元。故:對引用求地址,就是對目標變量求地址。引用本身不是對象所以不能定義引用的引用。*/

右值引用(必須要綁定到右值的引用)定義 類型 &&右值引用變量=右值表達式;

int &&a=10;//正確
int &&b=10*5;//正確10*5是右值
int &&c=a;//a的類型是int是左值

調用標準庫中定義的函數std::move() move()函數返回給定對象的右值引用, 可以顯式的將一個左值轉換爲對應的右值引用類型。

int &&c=move(a);//但是過程是銷燬a,a的右值由c接管。此後不能使用a,但可以給它賦新右值。

五.文件的輸入輸出

文件的讀寫
如果想以輸入方式打開,就用ifstream來定義;
如果想以輸出方式打開,就用ofstream來定義;
如果想以輸入/輸出方式來打開,就用fstream來定義

ofstream demo("demotest.txt"); 可以分成兩步
demo<<"demoout";
demo.close(); //完成操作後要關閉文件
ifstream demo("test.txt");  
char dchar;
demo>>dchar;//從文件中讀取一個字符
char dworld[80];
demo>>dworld;//從文件中讀取一個單詞
demo.getline(dworld,80);//從文件中讀取一行
string line;
getline(demo,line);//讀取一行轉換成字符串
fin.close();

區別

ifstream ifile;
ofstream ofile;
ofile<<"I Love You";//向文件寫入字符串"I Love You"
int i;
ifile>>i;//從文件輸入一個整數值。

字符串流stringstream是 C++ 提供的一個字符串流(stream),和iostream、fstream有類似的操作方式
istringstream 從string中讀取數據 定義 istringstream is(strs);
ostringstream 向string對象寫入格式化的內容。
stringstream 即可以讀取也可以寫入。

stringstream ss;
ss << "hello ";
ss << "world!";  // 對stringstream而言,operator<< 是一直往字符串流中寫字符,而不是覆蓋之前輸入的字符
cout << ss.str() <<endl;
/*str()函數創建的是一個臨時的string對象這個string對象在函數str()語句結束就會被銷燬,一般使用時應先聲明一個string對象s,將str()賦值給sconst string s=ss.str();或者const string& s=ss.str();這樣就“延長了臨時變量ss.str()的生命週期”,使得ss.str()生命結束時刻和s一樣*/

與容器一樣流不會降低自己空間,即使用了ss.clear()😭 清空操作如下 😦

ss.clear();//清空流
ss.str("");

六.range -for

for(int ele :{2,3,44,5,6,77})
{
	cout<<ele<<endl;
}
int arr []={1,2,3,4}
for(int ele :arr)
{
	cout<<ele<<endl;
}
vector<int > demo={1,2,3,4};//結合auto關鍵字可以方便地遍歷STL容器
for(auto ele:demo)
{
    cout<<ele<<endl<<;
}
 for(auto& ele:demo) 如果需要修改其中元素可以引用;
{
	ele+=2;
}

切記!!!!! 不能在遍歷容器時,改變容器的Size,即增刪元素。

七.函數

實參一定是確定值 不需要類型!!!

1.函數的參數

1)形參和實參
形參:在定義函數的時候,函數名後面小括號中的參數 , 格式: 數據類型 變量 如:int x;
形參的作用域:只能在本函數中使用
實參:調用函數的時候傳遞的參數

2)參數的傳遞的過程

實參的值拷貝一份放到函數形參中

3)函數傳參有三種傳參方式:傳值、傳址、傳引用

①按值傳遞
ⅰ形參和實參各佔一個獨立的存儲空間。
ⅱ形參的存儲空間是函數被調用時才分配的,調用開始,系統爲形參開闢一個臨時的存儲區,然後將各實參傳遞給形參,這是形參就得到了實參的值。
②地址傳遞
地址傳遞與值傳遞的不同在於,它把實參的存儲地址傳送給形參,使得形參指針和實參指針指向同一塊地址。因此,被調用函數中對形參指針所指向的地址中內容的任何改變都會影響到實參。
③引用傳遞
引用傳遞是以引用爲參數,則既可以使得對形參的任何操作都能改變相應數據,又使函數調用方便。引用傳遞是在形參調用前加入引用運算符“&”。引用爲實參的別名,和實參是同一個變量,則他們的值也相同,該引用改變則它的實參也改變。

2.函數的返回值

概念:執行函數體中的程序段,最後獲取的值並返回給主調函數,函數的返回值只能通過return 關鍵字進行返回
格式:return 表達式;/ return (表達式);
返回值類型要與返回值相同。
是否要定義形參看是否有未知內容參與運算,調用時實參必須對應.參數傳遞的是值。
函數中可以有多個return ,但是隻有一個起作用,因爲函數會結束後會帶回一個值。
函數調用和返回
函數調用會使程序的控制權傳遞給被調函數而當前活動會被掛起。
當前函數執行完成後主函數從調用語句之後的語句恢復執行。
函數在執行完函數體的最後一條語句或或遇到return語句時返回。

返回類型和return語句
return 語句形式

return;
 return表達式;

非void函數必須返回一個與聲明類型匹配的值否則會引起編譯錯誤。
返回值 默認情況下,函數的返回值是按值傳遞的,得到控制權的函數將接受return語句中指定的表達式值得副本。

返回引用(我覺得特別重要)

函數聲明爲返回引用,則不需要對return語句中的表達式進行復制,而是返回對象本身。
函數返回引用僅是它所指向對象的一個別名。

//找出s1和s2中比較短的一個並返回其引用
const string& shorter(const string& s1, const string& s2)
{	
return (s1.size() <= s2.size()) ? s1 : s2;
}
//函數返回結果時不會真正複製對象,返回的就是s1或s2本身。
string a=hello;
string b=word;
shorter(a,b)=“Hello”;//返回值爲引用。
cout<<a<<' '<<b;//Hello word;

注:對引用返回值的修改會改變實際返回的對象,爲了避免這種情況,可以將返回值聲明稱const。
不能返回自動局部對象的指針或引用:函數執行結束後,函數佔用的棧存儲空間被釋放,原本位於這段存儲空間中的局部對象和臨時變量都被釋放,返回的局部對象引用或指針指向不再有效的內存區域
重載函數
如果同一個作用域內的幾個函數名字相同但形參列表不同,則他們是重載函數
形參列表不同的概念:
1.形參數量不同
2.形參類型不同
3.常指針與指針不同,常引用與引用不同。
調用函數時如果存在多個重載函數,編譯器將根據函數調用中指定的實參進行選擇。
存儲類別 static靜態存儲
static對象在控制流程第一次到達其定義點時被初始化,如果沒有提供初始值就被自動初始化爲0;
在函數的後續調用中,初始化語句被跳過
靜態對象的值在函數被多次調用之間保持有效,生存期會延續到整個程序結束但他的作用於仍然是局部的,因此需要在同一函數的兩次調用之間保留某些數據時可以使用局部static對象。

八.指針

附博客 https://mp.csdn.net/mdeditor/86935527#
https://mp.csdn.net/mdeditor/87398537#

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