牛客微信推送的C++筆記:2016-12-12 14:23:26
1.C++不僅支持面向對象,也可以像C一樣支持面向過程.
2.OOP三大特性:封裝 繼承 多態
3.函數重載依據:函數類型and形參個數,返回類型不能作為依據
4.常成員函數是指通過函數獲得成員的值,不一定用const修飾返回值.
在程序設計中我們會經常調用函數,調用函數就會涉及參數的問題,那么在形參列表中const形參與非const形參對傳遞過來的實參有什么要求呢?
先來看一個簡單的例子:
- #include <iostream>
- #include <string>
- using namespace std;
- void print_str(const string s)
- {
- cout<<s<<endl;
- }
- int main()
- {
- print_str("hello world");
- return 0;
- }
毫無疑問,const實參傳遞給const形參,正確調用函數,如果你將第4行代碼中的const去掉,也能得到正確的結果。那么在去掉const的基礎上將形參變為引用形參,會出現什么樣的結果呢?看下面的代碼:
- #include <iostream>
- #include <string>
- using namespace std;
- void print_str( string & s)
- {
- cout<<s<<endl;
- }
- int main()
- {
- print_str("hello world");
- return 0;
- }
發現編譯不通過,如果在第4行的string前加上一個const,就會通過編譯。進一步研究我們會發現指針形參與引用形參會出現類似的情況。普通形參加不加const限定符對實參沒有影響,引用形參和指針形參前面沒有const限定符時,實參必須是非const的,而前面有const限定符時對實參也沒有什么影響。
為什么會出現這種情況?
原因在於實參的傳遞方式不同,函數中的形參是普通形參的時,函數只是操縱的實參的副本,而無法去修改實參,實參會想,你形參反正改變不了我的值,那么你有沒有const還有什么意義嗎?引用形參和指針形參就下不同了,函數是對實參直接操縱,沒有const的形參時實參的值是可以改變的,這種情況下怎能用函數來操縱const實參呢。我一直這樣記憶:“對於變量的約束,允許加強,當絕對不能削弱.....”例如:實參是const,那么形參如果是非const意味着可以在函數體中改變形參的值,使約束削弱了所以不行。對於使用&,自然也是這個道理。同樣的,指針里面的const也是這個樣子的,如果讓非const指針指向了const對象的地址,那么必然是無法通過編譯的,因為如果這樣做了,意味着可以通過這個指針改變本該是const的值了,顯然是使約束削弱了
5.引用就是取別名
6.名稱空間防止命名沖突
7.private修飾函數和成員
8.inline內聯函數
9.構造函數只負責初始化,不負責分配對象占用內存空間
10.構造函數能夠重載,析構函數沒有形參.
11.所有成員默認訪問屬性 private
12.引用類的目的:提供一個機制,實現從現實世界到程序世界的映射 提供代碼重用性 數據封裝
13.定義類 訪問屬性: 定義結束;
14.指針無論類型4字節
15.this指針是數據區中的數據和代碼區中的函數連接的紐帶,this指針作用於作用域的類內部 this指針作為非靜態成員函數的隱含形參,編譯器自動添加。
舉個栗子:
dataSetMonth(9);<=>SetMonth(&date,9);
返回對象類本身
return *this;
當參數與成員名相同時,不能用n=n,需用this->n=n;
this指針實例:
class Point { int x, y; public: Point(int a, int b) { x = a; y = b; } void MovePoint(int a, int b) { x += a; y += b; } void print() { cout << "x=" << endl; } }; int main() { Point point1(10, 10); point1.MovePoint(2, 2); point1.print(); }
MovePoint函數中,x+=a <=> this->x+=a;x+=b <=> this->x+=b;
類的this指針的特點
(1) this只能在成員函數中使用 全局函數、靜態函數都不能使用this 成員函數默認第一個參數為T* const this
舉個栗子
class A { public: int func(int p) { } };
編譯器認為是int func(A *const this,int p);
16.拷貝構造函數完成類對象的拷貝 CExample B=A; 系統為B對象分配了內存並完成了對A對象的復制
舉個栗子
#include <iostream> using namespace std; class CExample { private: int a; public: CExample(int b) { a = b; } CExample(const CExample& C) { a = C.a; } void show() { cout << a << endl; } }; int main() { CExample A(100); CExample B = A; B.show(); return 0; }
CExample(const CExample& C)就是我們定義的拷貝構造函數.拷貝構造函數就是一種特殊的構造函數,函數的名稱必須和類名稱一致,必須的一個參數是本類型的引用變量.
17.圓形類的實現
#include <cmath> #include "circle.h" Circle::Circle(double aX, double aY, double aR) :m_iX(aX), m_iY(aY), m_iRadius(aR){} Circle::~Circle(){} void Circle::setPos(double aX, double aY) { m_iX = aX; m_iY = aY; } void Circle::getPos(double &rX, double &rY)const { rX = m_iX; rY = m_iY; } double Circle::getRadius()const { return m_iRadius; } double Circle::getDist(const Circle & aRef)const { double x1, y1, x2, y2; this->aRef.getPos(x1, y1); double r = pow(x1 - x2, 2); r += pow(y1 - y2, 2); return sqrt(r); } bool Circle::isInter(const Circle & aRef)const { double min_dist = this->getRadius() + aRef.getRadius(); double dist = this->getDist(aRef); if (min_dist >= dist) { return true; } return false; }
18.動態數組類的實現
#ifndef ARRAY_H #define ARRAY_H #include <iostream> class Array { public: Array(const int aCount = 10); Array(const Array &aArray); ~Array(); void setCount(const int aCount); int getValue(const int aIndex)const; void setValue(const int aIndex, const int aValue); private: int m_iCount, *m_pArray; }; #endif Array:Array(const int aCount) : m_iCount(aCount), m_pArray(NULL) { if (aCount <= 0) { return false; } m_pArray = new int[aCount]; } Array:Array(const Array &aArray) : m_iCount(aArray.m_iCount), m_pArray(NULL) { if (aArray.m_iCount <= 0) { return false; } this->m_pArray = new int[aArray.m_iCount]; for (int I = 0; i < m_iCount; i++) { m_pArray[i] = aArray.m_pArray[i]; } } Array::~aArray() { delete[]m_pArray; } void Array::setCount(const int aCount) { if (!aCount) { return false; } int min_count = (aCount < m_iCount) ? aCount : m_iCount; m_iCount = aCount; int *nArray = new int[aCount]; if (min_count) { memcpy(nArray, m_pArray, min_count*sizeof(int)); } delete[]m_pArray; m_pArray = nArray; } int Array::getValue(const int aIndex)const { return m_pArray[aIndex]; } void Array::setValue(const int aIndex, const int aValue) { if (!m_pArray) { return false; } if (aIndex >= m_iCount) { return false; } m_pArray[aIndex] = aValue; }
19.復數類的實現
Complex::Complex(double aReal, double aImag) { m_dImag = aImag; m_dReal = aReal; } Complex::~Complex(){} double Complex::GetReal()const { return m_dReal; } double Complex::GetImag()const { return m_dImag; } Complex Complex::Add(Complex &aRef)const { Complex result; result.m_dImag = m_dImag + aRef.m_dImag; result.m_dReal = m_dReal + aRef.m_dReal; return result; } 20.字符串類的實現 #include <iostream> using namespace std; class String{ public: String(const char* str = NULL); String(const String &other); ~String() { delete[]m_data; } void display()const; private: char *m_data; }; String::String(const char* str) { if (!str) { m_data = 0; } else { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } } String::String(const String & other) { if (this != &other) { m_data = new char[strlen(other.m_data) + 1]; strcpy(m_data, other.m_data); } } void String::display()const { cout << m_data << endl; }
21.友元類 友元關系不能被繼承 單向不具備交換性 不具有傳遞性
22.指針與const 划線法 const 與 指針關系 左變指向 右變數據 雙雙凍結
23.構造函數是特殊的成員函數,重點注意與類同名、無返回類型、有形參表(可為空)、函數體.
一個類可以有多個構造函數,但形參數目或類型不能均同.形參指定了初始化式.
24.顯示定義一個構造函數:沒有形參的默認構造函數.默認構造函數,無顯示初始化式.
舉個栗子
vector<int> vi; //無元素向量對象
string s; //空字符串
Sales_item item; //空的Sales_item對象
25.構造函數Public,不可以Private.否則不能初始化對象.
26.函數重載是為了用一個函數名實現不同函數功能.
27.函數重載和重復聲明有區別.形參表和返回類型一致,就近采用,單一聲明.同表不同型,第一正確.
1、進程與線程的區別
(1)粒度性分析:線程的粒度小於進程。
(2)調度性分析:進程是資源擁有的基本單位,線程是獨立調度與獨立運行的基本單位,出了寄存器,程序計數器等必要的資源外基本不擁有其他資源。
(3)系統開銷分析:由於線程基本不擁有系統資源,所以在進行切換時,線程切換的開銷遠遠小於進程。
2、進程的狀態及其轉換

3、進程同步與互斥的區別
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源。
簡單地說:同步體現的是一種協作性,互斥體現的是一種排他性。
4、進程間的通信方式有哪些?
(1)管道( pipe ):管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。
(2)有名管道 (named pipe) :有名管道也是半雙工的通信方式,但是它允許無親緣關系進程間的通信。
(3)信號量( semophore ) :信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。
(4)消息隊列( message queue ) :消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。
(5)信號 ( sinal ) :信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生。
(6)共享內存( shared memory ) :共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。
(7)套接字( socket ) :套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同及其間的進程通信。
5、作業(或進程)的調度算法有哪些?
(1)先來先服務(FCFS,First-Come-First-Served): 此算法的原則是按照作業到達后備作業隊列(或進程進入就緒隊列)的先后次序來選擇作業(或進程)。
(2)短作業優先(SJF,Shortest Process Next):這種調度算法主要用於作業調度,它從作業后備隊列中挑選所需運行時間(估計值)最短的作業進入主存運行。
(3)時間片輪轉調度算法(RR,Round-Robin):當某個進程執行的時間片用完時,調度程序便停止該進程的執行,並將它送就緒隊列的末尾,等待分配下一時間片再執行。然后把處理機分配給就緒隊列中新的隊首進程,同時也讓它執行一個時間片。這樣就可以保證就緒隊列中的所有進程,在一給定的時間內,均能獲得一時間片處理機執行時間。
(4)高響應比優先(HRRN,Highest Response Ratio Next): 按照高響應比((已等待時間+要求運行時間)/ 要求運行時間)優先的原則,在每次選擇作業投入運行時,先計算此時后備作業隊列中每個作業的響應比RP然后選擇其值最大的作業投入運行。
(5) 優先權(Priority)調度算法: 按照進程的優先權大小來調度,使高優先權進程得到優先處理的調度策略稱為優先權調度算法。注意:優先數越多,優先權越小。
(6)多級隊列調度算法:多隊列調度是根據作業的性質和類型的不同,將就緒隊列再分為若干個子隊列,所有的作業(或進程)按其性質排入相應的隊列中,而不同的就緒隊列采用不同的調度算法。
6、死鎖產生的原因,死鎖產生的必要條件是什么,如何預防死鎖,如何避免死鎖,死鎖定理?
死鎖產生的原因:(1)競爭資源;(2)進程推進順序不當。
死鎖產生的必要條件:
(1)互斥條件:一個資源一次只能被一個進程所使用,即是排它性使用。
(2)不剝奪條件:一個資源僅能被占有它的進程所釋放,而不能被別的進程強占。
(3)請求與保持條件:進程已經保持了至少一個資源,但又提出了新的資源要求,而該資源又已被其它進程占有,此時請求進程阻塞,但又對已經獲得的其它資源保持不放。
(4)環路等待條件:當每類資源只有一個時,在發生死鎖時,必然存在一個進程-資源的環形鏈。
預防死鎖:破壞四個必要條件之一。
死鎖的避免:銀行家算法,該方法允許進程動態地申請資源,系統在進行資源分配之前,先計算資源分配的安全性。若此次分配不會導致系統從安全狀態向不安全狀態轉換,便可將資源分配給進程;否則不分配資源,進程必須阻塞等待。從而避免發生死鎖。
死鎖定理:S為死鎖狀態的充分條件是:尚且僅當S狀態的資源分配圖是不可完全簡化的,該充分條件稱為死鎖定理。
死鎖的解除:
(1)方法1:強制性地從系統中撤消一個或多個死鎖的進程以斷開循環等待鏈,並收回分配給終止進程的全部資源供剩下的進程使用。
(2)方法2:使用一個有效的掛起和解除機構來掛起一些死鎖的進程,其實質是從被掛起的進程那里搶占資源以解除死鎖。
7、分段式存儲管理、分頁式存儲管理,兩個的區別?
分段式存儲管理:分頁存儲管理是將一個進程的地址(邏輯地址空間)空間划分成若干個大小相等的區域,稱為頁,相應地,將內存空間划分成與頁相同大小(為了保證頁內偏移一致)的若干個物理塊,稱為塊或頁框(頁架)。在為進程分配內存時,將進程中的若干頁分別裝入多個不相鄰接的塊中。
分頁式存儲管理:在分段存儲管理方式中,作業的地址空間被划分為若干個段,每個段是一組完整的邏輯信息,如有主程序段、子程序段、數據段及堆棧段等,每個段都有自己的名字,都是從零開始編址的一段連續的地址空間,各段長度是不等的。
兩者的區別:
1、頁是信息的物理單位,分頁是為了實現非連續的分配,以便解決內存的碎片問題,或者說分頁是為了由於系統管理的需要。
2、頁的大小固定是由系統確定的,將邏輯地址划分為頁號和頁內地址是由機器硬件實現的。而段的長度是不固定的,決定與用戶的程序長度,通常由編譯程序進行編譯時根據信息的性質來划分。
3、分頁式存儲管理的作業地址空間是一維的,分段式的存儲管理的作業管理地址空間是二維的。
8、頁面置換算法有哪些?
(1)最佳置換算法(Optimal):即選擇那些永不使用的,或者是在最長時間內不再被訪問的頁面置換出去。(它是一種理想化的算法,性能最好,但在實際上難於實現)。
(2)先進先出置換算法FIFO:該算法總是淘汰最先進入內存的頁面,即選擇在內存中駐留時間最久的頁面予以淘汰。
(3)最近最久未使用置換算法LRU(LeastRecently Used):該算法是選擇最近最久未使用的頁面予以淘汰,系統在每個頁面設置一個訪問字段,用以記錄這個頁面自上次被訪問以來所經歷的時間T,當要淘汰一個頁面時,選擇T最大的頁面。
(4)Clock置換算法:也叫最近未用算法NRU(Not RecentlyUsed)。該算法為每個頁面設置一位訪問位,將內存中的所有頁面都通過鏈接指針鏈成一個循環隊列。當某頁被訪問時,其訪問位置“1”。在選擇一頁淘汰時,就檢查其訪問位,如果是“0”,就選擇該頁換出;若為“1”,則重新置為“0”,暫不換出該頁,在循環隊列中檢查下一個頁面,直到訪問位為“0”的頁面為止。由於該算法只有一位訪問位,只能用它表示該頁是否已經使用過,而置換時是將未使用過的頁面換出去,所以把該算法稱為最近未用算法。
(5)最少使用置換算法LFU:該算法選擇最近時期使用最少的頁面作為淘汰頁。
