1. 程式人生 > >總結知識點(未完結)

總結知識點(未完結)

知識點一、C語言與C++的區別是什麼?

1)C語言是面向過程,以事件為中心,採用自頂向下順序執行,逐步求精。程式結構可劃分為若干個功能模組,模組內部一般由順序、選擇和迴圈三種基本結構組成。模組形成樹狀結構,功能相對獨立。利用子函式實現模組,而程式流程在寫程式時就已經決定。舉例子,五子棋。

2)C++語言是面向物件,把資料及對資料的操作方法放在一起,作為一個整體物件。對同類物件抽象出其共性,即類。類中的大多數資料,只能被本類的方法進行處理。類通過一個簡單的外部介面與外界發生關係。程式流程由使用者在使用中決定。舉例子,人。

3)面向物件用符合常規思維方式,處理客觀世界的問題,強調把問題的要領直接對映到物件及物件之間的介面上。面向過程強調過程的抽象化與模組化,以時間為中心構造處理客觀問題。

4)面向物件方法是用計算機邏輯來模擬客觀實踐中的物理存在,以物件的集合類作為處理問題的基本單元,用類的層次結構來體現類之間的繼承和發展。面向過程處理問題的基本單位是模組,用模組的層次結構概括模組與模組間的關係和功能

5C++的基本特徵有三個:封裝,繼承和多型。

1)封裝:本質上是對客觀事物的抽象。將客觀事物抽象成類,採用類來描述客觀事物的過程,實現了介面和實現的分離。

2)繼承:是一個從一般到特殊的過程。可以使用現有類的所有功能,而不需要重新編寫原來的類。目的是為了進行程式碼複用和支援多型。通過繼承建立的新類成為派生類,被繼承的類成為基類。

3)多型:簡單概括就是“一個介面,多種方法”。從實現的角度來講,多型可以分為兩類:編譯時的多型性和執行時的多型性。前者是通過靜態聯編來實現的,比如C++

中通過函式的過載和運算子的過載。後者則是通過動態聯編來實現的,在C++中執行時的多型性主要是通過虛擬函式來實現的。可以將父物件設定成為和一個或更多個子物件相等的技術賦值後,父物件可以根據當前賦值給它的子物件的特性以不同方式執行。簡單來說,就是允許將基類指標或引用型別繫結到子類物件(稱作派生類到基類的隱式轉換,基類到派生類不存在隱式轉換)。

知識點二、大端儲存與小端儲存

嵌入式系統開發者應該對Little-endianBig-endian模式非常瞭解。

採用Little-endian模式的CPU對運算元的存放方式是從低位元組到高位元組,而Big-endian模式對運算元的存放方式是從高位元組到低位元組。

例如,16bit寬的數0x1234Little-endian模式CPU記憶體中的存放方式(假設從地址0x4000開始存放)為:

4)記憶體地址

5)0x4000

6)0x4001

7)存放內容

8)0x34

9)0x12

而在Big-endian模式CPU記憶體中的存放方式則為:

10)記憶體地址

11)0x4000

12)0x4001

13)存放內容

14)0x12

15)0x34

32bit寬的數0x12345678Little-endian模式CPU記憶體中的存放方式(假設從地址0x4000開始存放)為:

16)記憶體地址

17)0x4000

18)0x4001

19)0x4002

20)0x4003

21)存放內容

22)0x78

23)0x56

24)0x34

25)0x12

而在Big-endian模式CPU記憶體中的存放方式則為:

26)記憶體地址

27)0x4000

28)0x4001

29)0x4002

30)0x4003

31)存放內容

32)0x12

33)0x34

34)0x56

35)0x78

請寫一個C函式,若處理器是Big_endian的,則返回0;若是Little_endian的,則返回1

解答:

int checkCPU( )

{

    {

           union w

           { 

                  int a;

                  char b;

           } c;

           c.a = 1;

           return(c.b ==1);

    }

}

聯合體union的存放順序是所有成員都從低地址開始存放,面試者的解答利用該特性,輕鬆地獲得了CPU對記憶體採用Little-endian還是Big-endian模式讀寫。如果誰能當場給出這個解答,那簡直就是一個天才的程式設計師。

知識點三、下列類宣告正確嗎?

class A   {  const int size=0;  }

解析:類中的常量有兩種實現方式:1)在建構函式的初始化列表中初始化變數;2)將常量設定成static型別。

class A   {  A() {  const int size=0;  }  }

或者class A {  static const int size =0;  }

知識點四、編寫類string的建構函式、解構函式和賦值函式。

string的原型:

class string

{

public:

    string(const char *str=NULL);//普通建構函式

    string(const string &other);//拷貝建構函式

    string& operator=(const string &other);//拷貝賦值函式

    ~string(void);//解構函式

private:

    char *m_data;//用於儲存字串

};


1)建構函式

   實現功能,根據一個字串常量建立一個MyString物件。建構函式中,首先分配了足量的記憶體,然後將這個字串常量複製到這個記憶體中。

//string類的建構函式

string::string(const char *str)

{

   if(str==NULL)

   {

        m_data=new char[1];

        *m_data='\0';

   }

   else

   {

       int n=strlen(str);//計算輸入字串的長度

       m_data=new char[n+1];//申請記憶體大小

       strcpy(m_data,str);

   }

}

2)拷貝建構函式

   拷貝建構函式可以在函式呼叫中以傳值方式傳遞一個MyString引數;還可以在函式以值形式,返回MyString物件時,實現“返回值賦值”

//string類的拷貝建構函式

string::string(const string &other)

{

    int n=strlen(other.m_data);

    m_data=new char[n+1];

    strcpy(m_data,other.m_data);

}

3)拷貝賦值函式

拷貝賦值函式可實現字串的傳值活動

//string類的拷貝賦值函式

string& string::operator=(const string &other)

{

  //檢查自賦值

  if(this==&other)

        return *this;

  //釋放原有資源

  delete [] m_data;

   m_data=NULL;

  //分配新的記憶體資源,並複製內容

  int n=strlen(other.m_data);

  m_data=new char[n+1];

  strcpy(m_data,other.m_data);

  //返回本物件的引用

  return *this;

}

4)解構函式

   為了防止記憶體洩漏,還需要定義一個解構函式。當一個物件超出它的作用域時,由解構函式釋放它所佔用的記憶體。

//string類的解構函式

string::~string(void)

{

    delete [] m_data;

}


知識點十六、拷貝賦值函式和拷貝建構函式

1拷貝賦值函式:將一個類物件賦予給同一型別的物件時,應該做什麼。

   實質是,過載了賦值運算子,如果沒有定義拷貝賦值函式,則編譯器會自動合成一個。

   返回值型別:返回一個該型別的引用,並在函式結束前,返回自身的引用(即*this)。只有返回一個引用,才允許連續賦值。

   函式名關鍵字operator=

傳入引數:傳入型別宣告為常量引用,否則,將函式形參複製到實參會呼叫一次賦值建構函式,引起不必要的消耗。

注意:1要釋放例項自身已有的記憶體分配新記憶體前,必須先釋放自身已有記憶體,否則,會引起記憶體洩漏。

2判斷傳入引數和當前例項(*this)是不是同一個例項如果是,則直接返回當前例項即可。

教材給的解法見上題,考慮異常安全性的解法。常規解法,當檢測到傳入引數與當前例項不一致時,首先釋放了例項m_data的記憶體。下一步,重新申請記憶體時,若出現記憶體不足,則會導致丟擲異常,m_data將成為一個空指標,這樣容易導致程式崩潰。

也就是說,在拷貝賦值函式中丟擲異常,CMyString的例項不再保持有效狀態,違背了異常安全性原則。

如下所示:首先建立一個臨時例項,再交換臨時例項和原來的例項。

CMyString& operator=(const CMyString &str)

{

  if(this!=&str.m_data)

  {

CMyString strtemp(str);   //直接初始化strtemp

     //程式執行到if語句後,區域性變數strtemp會自動呼叫解構函式

char *temp=strtemp.m_data;

strtemp.m_data=m_data;

m_data=temp;

  }

  return *this;

}

2、拷貝建構函式:用同類型的一個物件,初始化本物件時做什麼。

   本質還是建構函式,如果沒有定義拷貝賦值函式,則編譯器會自動合成一個。

   無返回型別,函式名與類同名,傳入引數:必須是同類型的常量引用。

原因:若拷貝建構函式傳入引數是一個類的例項,即傳值引數。此時把形參複製到實參,需要呼叫拷貝建構函式。因此,如果允許拷貝建構函式進行值傳遞,就會在拷貝建構函式中呼叫拷貝建構函式,就會形成無休止的遞迴呼叫從而引起棧溢位。因此不允許傳值引數。

注意:1)引用型別和const型別必須初始化。

2)已知fun(int)是類Test的公有成員函式,p是指向成員函式fun()的指標,採用( )是正確的。p=&Test::fun

3常見的檔案系統,系統函式:

1. fcntil 檔案控制

2. open 開啟檔案

3. creat 建立新檔案

4. close 關閉檔案描述字

5. read 讀檔案

6. write 寫檔案

7. readv 從檔案讀入資料到緩衝陣列中

8. writev 將緩衝數組裡的資料寫入檔案

9. pread 對檔案隨機讀

10.pwrite 對檔案隨機寫

知識點五、複製建構函式與賦值運算子的區別

複製建構函式總的來說是建構函式,用於完成基於同一類的其他物件的構建及初始化

特點:1)函式名與類名相同,且無返回型別;

2)只有一個引數,並且為自身型別的引用;

3)每個類必須有一個複製建構函式,若未顯示定義,則編譯器生成一個合成建構函式;

4)目的是新建一個物件例項。保證新建物件有獨立記憶體空間,不能與先前物件共用記憶體。

賦值操作符,用於用已存在的物件來建立另一個物件,且給物件賦予新值

複製建構函式與賦值運算子的不同如下:

1)複製建構函式生成新的類物件,而複製運算子則不能。

2)前者用於生成新型別,所以初始化物件之前不用檢測源物件是否和新建物件相同;

   而後者需要,且如果原物件中有記憶體分配,要先把記憶體釋放掉。

3)當類中有指標型別的成員變數時,一定要重寫複製建構函式和賦值建構函式,不能使用預設。

知識點六、overload(過載)override(覆蓋)的區別

Overload(過載),是指編寫一個函式與已有函式的函式名相同,但是引數列表不同。

引數列表不同,指引數型別、個數和順序,至少一項不同;對於過載函式的呼叫,在編譯期間就已經確定,是靜態的;例如一個函式既可以接收整型數作為引數,也可以接收浮點型數作為引數。注意:過載不關心返回值型別!!!

Override(覆蓋),是指派生類重寫基類的虛擬函式,重寫的函式必須有一致的返回值型別、函式名和引數表;覆蓋發生在函式的執行階段

知識點七、C++中繼承的成員變數的覆蓋/重寫

首先需要明白:

1)成員函式的覆蓋,是指子類對父類虛擬函式的覆蓋,必須要求函式返回型別、函式名和引數列表同時一致。

2)成員變數的覆蓋,子類覆蓋的僅僅是繼承來的成員變數,並不改變原來父類的成員變數。

3)建構函式從基類開始構造,各個類的同名變數沒有形成覆蓋,都是單獨的變數。子類呼叫遵循就近原則:如果自己有則首先呼叫自己的函式;如果自己沒有,父類存在相關介面則優先呼叫;如果父類不存在,則呼叫祖父類介面。

舉例:(詳見程式設計師面試寶典4--P134 and C++ prime(第五版)P550

知識點八、友元

一句話:能夠訪問類中的私有成員變數的非成員函式。使用友元函式時,需要注意以下幾個方面:

1)必須在類中宣告友元函式:關鍵字friend+友元函式原型;在類外部定義友元函式

2)友元函式不能直接訪問類的成員,只能訪問物件成員。所以,呼叫友元,需要指明物件。

3)友元函式不是成員函式,所以類與類之間的友元關係不能繼承

//寫一個程式,設計一個點類point,求兩個點之間的距離(利用友元)

class point

{

public:

    point(float a=0.0f,float b=0.0f):x(a),y(b) {};

    friend float distance(point& left,point& right)

private:

    float x;

    float y;

};

friend float distance(point& left,point& right)

{

    return ((left.x-right.x)^2+(left.y-right.y)^2)^0.5;

}

知識點九、記憶體分類

C/C++程式設計中,經常需要操作的記憶體分為以下幾類:
棧區(stack:用於存放程式臨時建立的區域性變數,如函式的引數值、區域性變數值等,由編譯器自動分配釋放。
堆區(heap一般由程式設計師申請和釋放。用於存放程序執行中被動態分配的記憶體段,大小不固定,可動態擴張或縮減。若程式設計師不釋放,程式結束時,可能由作業系統回收,但最好還是由程式設計師釋放。注意:它與資料結構中的堆是兩回事,分配方式類似資料結構中的連結串列。
全域性區(靜態區static全域性變數和靜態變數的儲存是放在一起的。初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性和未初始化的靜態在鄰近的另一塊區域。程式結束後由系統釋放。 
文字常量區
:存放字串常量,程式結束後由系統釋放。
程式程式碼區:存放函式體內的二進位制程式碼

heapstack的區別?
1heap是堆,stack是棧。堆一般由程式設計師手動分配釋放,棧是由作業系統自動分配釋放。
2stack的空間有限,在window下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體區域,大小一般為2M;堆是向高地址擴充套件的資料結構,是不連續的記憶體區域,因為由系統用連結串列來儲存空閒記憶體空間,堆的大小取決於系統的有效虛擬記憶體,有很大的自由儲存區。
3stack由系統自動分配,速度較快。Heapnew分配,一般速度比較慢,而且容易產生記憶體碎片。