C++精華筆記


牛客微信推送的C++筆記:2016-12-12   14:23:26

1.C++不僅支持面向對象,也可以像C一樣支持面向過程.

2.OOP三大特性:封裝 繼承 多態

3.函數重載依據:函數類型and形參個數,返回類型不能作為依據

4.常成員函數是指通過函數獲得成員的值,不一定用const修飾返回值.

在程序設計中我們會經常調用函數,調用函數就會涉及參數的問題,那么在形參列表中const形參與非const形參對傳遞過來的實參有什么要求呢?

先來看一個簡單的例子:

  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4. void print_str(const string s)  
  5. {  
  6.       cout<<s<<endl;  
  7. }  
  8. int main()  
  9. {     
  10.       print_str("hello world");  
  11.       return 0;  
  12. }  


毫無疑問,const實參傳遞給const形參,正確調用函數,如果你將第4行代碼中的const去掉,也能得到正確的結果。那么在去掉const的基礎上將形參變為引用形參,會出現什么樣的結果呢?看下面的代碼:

  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4. void print_str( string & s)  
  5. {  
  6.       cout<<s<<endl;  
  7. }  
  8. int main()  
  9. {     
  10.       print_str("hello world");  
  11.       return 0;  
  12. }  

發現編譯不通過,如果在第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)先來先服務(FCFSFirst-Come-First-Served: 此算法的原則是按照作業到達后備作業隊列(或進程進入就緒隊列)的先后次序來選擇作業(或進程)。

2)短作業優先(SJF,Shortest Process Next):這種調度算法主要用於作業調度,它從作業后備隊列中挑選所需運行時間(估計值)最短的作業進入主存運行。

3)時間片輪轉調度算法(RRRound-Robin):當某個進程執行的時間片用完時,調度程序便停止該進程的執行,並將它送就緒隊列的末尾,等待分配下一時間片再執行。然后把處理機分配給就緒隊列中新的隊首進程,同時也讓它執行一個時間片。這樣就可以保證就緒隊列中的所有進程,在一給定的時間內,均能獲得一時間片處理機執行時間。

4)高響應比優先(HRRNHighest 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)最近最久未使用置換算法LRULeastRecently Used):該算法是選擇最近最久未使用的頁面予以淘汰,系統在每個頁面設置一個訪問字段,用以記錄這個頁面自上次被訪問以來所經歷的時間T,當要淘汰一個頁面時,選擇T最大的頁面。

 

4Clock置換算法:也叫最近未用算法NRU(Not RecentlyUsed)。該算法為每個頁面設置一位訪問位,將內存中的所有頁面都通過鏈接指針鏈成一個循環隊列。當某頁被訪問時,其訪問位置“1”。在選擇一頁淘汰時,就檢查其訪問位,如果是“0”,就選擇該頁換出;若為“1”,則重新置為“0”,暫不換出該頁,在循環隊列中檢查下一個頁面,直到訪問位為“0”的頁面為止。由於該算法只有一位訪問位,只能用它表示該頁是否已經使用過,而置換時是將未使用過的頁面換出去,所以把該算法稱為最近未用算法。

5)最少使用置換算法LFU該算法選擇最近時期使用最少的頁面作為淘汰頁。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM