天天看點

C++: 主要知識點

  大學期間,學了一學期的C語言,當然包括學習資料結構時,用的也是C語言。當時剛剛接觸計算機,對于程式設計更是一無所知。上課學習學習,偶爾會照着書上敲一下代碼。大二下學期,就丢掉了不用了。最近由于工作的需要,要使用Java Native Interface,是以就學習了1天半的C++,對C++有了一點點的了解,寫一下自己的了解。

     一天半時間,也學不多少東西,我主要就搞明白了下面幾個問題:

1)指針

  這麼多年了,還記得在C語言時,最難以了解的,應該屬于指針了。還記得譚浩強的那本C語言書(書名是啥,真的忘了。不過作者譚浩強老師,絕大多數的中國開發人員應該都知道的),前面大部分用的都是基本資料類型(也就是Java中的原生類型),後面一小部分突然講起了指針,當時立馬就 蒙 圈了。不過好在最後還是了解了指針,雖然後來又忘記了。

指針是什麼?

指針是一個存放另外一個東西的位址的變量。指針是一個變量,把一個具有特殊作用的變量稱為指針。它的特殊作用就是:存放另外一個東西的記憶體位址。也就是說指針變量的值代表了一個位址,這個位址是另外一個東西的。那另外一個東西是什麼呢?就是我們說的對象(或者執行個體)。在C++中,還為這個對象起了一個别名:引用。

總結一下就是:指針變量指向一個對象(或者引用)。

*、&的使用

在聲明語句中:

*表示聲明的是指針,&表示引用。

這裡說的聲明語句,可以是變量聲明,也可以是函數聲明中。在函數聲明中,傳回值、函數名、參數都可以聲明為指針。

在使用指針變量時,

(* 變量名)代表取對象。(& 引用)代表取指針。

void personTest(Person * p){
    if(p!=NULL){
        p->setAddress("Bei Jing, Hai Dian"); // 采用指針的方式指派
        (*p).setName("Fang JiNuo");    // 采用對象的方式指派。
        (*p).setAge(23);
        printf("show info:\n%s\n", (*p).toString());
        delete p;
        p=NULL;
    }
}      

函數指針、指針函數 

       這個兩個詞八個字,不知道有多少人載了跟頭,其實很好了解了。中國人說話,多以叙述的方式為主。這個兩個詞都是省略句,不過省略的是助詞。

函數指針全名是:函數名是指針。

指針函數全名是:傳回值是指針的函數。

這兩個中,指針函數很容易了解了:

char * func(char[] p);這個函數就是一個指針函數。

函數指針,函數名是指針。指針也是變量,是以就可以了解為:函數名是變量。

下面是一個函數指針變量的聲明:

typedef int (* func) (int x);

然後把這個變量作為另外一個函數的參數來使用:

typedef int (*func)(int arg); // 定義一個函數指針

/* 一個函數指針的實作
* funcImpl就可以作為func的值進行指派。
 */
int funcImpl(int arg){
    return arg;
}

/* 
* 聲明一個函數,将函數指針作為函數call的參數
 */
void call(func f){
    for(int i=0; i<10; i++){
        cout << f(i) << endl;
    }
}

// 進行測試
int main(int argc, char* args[])
{
    call(funcImpl);
}      

程式執行結果是,列印出0到9。 

這個函數指針與下面JavaScript的代碼有同樣的作用:

function funcImpl(int num){
    return num;
}
(function call(f){
    if(f){
        if(f instanceof Function){
            for(int i=0; i<10; i++){
               alert(f(i));
            }
        }
     }
})(funcImpl);      

當然了與下面的Java代碼代碼也是一樣的: 

interface Callback{
    int doCall(int num);
}

static void call(Callback callback){
    if(callback==null) return;
    for(int i=0; i<10; i++){
        System.out.println(callback.doCall(i));
    }
}

public static void main(string[] args ){
    call(new Callback(){
       public int doCall(int num){
          return num;
       }
     });
}      

在C#中,它還有另外一個名字,delegate。 

 其實它們都是傳說中的鈎子函數callback。

2)頭檔案、#include

       在大學時,沒有寫過頭檔案,也沒有看過頭檔案。是以頭檔案對我來說,一直是個謎。不過在學習了Java、C#後,就自然而然的會将#include 頭檔案了解為import、using等。

       那麼頭檔案中,會寫什麼呢?

       一般來說,會将聲明(類中的字段、方法的聲明)寫在.h檔案中,将方法的實作,寫在cpp檔案中。以此來達到接口與實作的分離。其他地方使用#include時,就隻會看到.h檔案中的聲明,看不到具體的實作。

       另外要說的是#include的兩種方式。 例如#include <xxxx.h>、#include “xxxx.h”。這兩種方式,還是有差別的,<>方式是先從系統目錄下找.h檔案,” ”則是先從使用者目錄下去找.h檔案。有點類似于Java中ClassLoader了,預設采用委托加載,也可以使用子類優先方式進行加載。

建立執行個體與回收

       在C語言中,聲明一個變量,可以直接使用聲明的方式、也可以使用malloc的方式。

在C++中,又加入了一種new的方式,這種方式的寫法與Java中是一樣的。

建立 釋放
聲明(隐式):建立的是對象本身,而不是指針 隐式釋放,不需要通過寫代碼。因為聲明的對象在棧内,出棧後自動釋放
malloc(顯示):該方法用于配置設定記憶體,傳回值是指針 使用free()進行釋放
new :配置設定記憶體,傳回值是指針 使用delete 進行釋放

Malloc、new 配置設定記憶體後,傳回值都是指針。且配置設定在記憶體中Heap區,不會自動釋放,是以需要使用free、delete進行釋放。

 另外在使用feee、delete後,最好是将指針的值設定為NULL, 因為free、delete隻是釋放了對象占用的記憶體空間,而指針的值仍然是對象在被釋放前占用空間的首位址。

 這與Java是不同的,Java能夠自動的進行回收。對象設定為null即可。Java中的回收機制是:采用分代回收算法對于不可達的對象進行回收。

void fun(){
    Menu* m1=new Menu();  // 顯式聲明對象
    Menu m2;              // 隐式聲明對象
    this->menulist->push_back(m1);
    this->menulist->push_back(&m2);
}

void showList(){
    list<Menu*>::iterator iter=this->menulist->begin();
    while(iter!=this->menulist->end()){
        Menu* menu=*iter; 
        cout << m->toString() << endl;
        iter++;
    }
}      

這段代碼,在編譯時,是沒有問題的,也就是說從寫法來講,沒有錯誤的。但是在執行showList()時就會出現空指針異常。原因如下: 

在fun()中,建立的m1在heap中,不會自動的釋放,建立的m2,在stack中,會自動的釋放,當fun執行完畢時m2對象實際已經不存在了。然後執行showList()時,變量到m2對象時,肯定空的了,list中存儲的m2的指針,已經成為野指針了。

3)namespace

命名空間,在大多數語言中都有的。他們的作用都是為了區分。

//定義命名空間

namespace ns{

    // your code

}

// 導入命名空間:

using namespace std;

// 使用命名空間:

std::xxxx

4)#define 、typedef

typeof 是為已有類型取别名。在編譯階段有效,由于是在編譯階段,是以typedef有類型檢查的功能。

#define是宏定義,發生在預處理階段,也就是編譯之前,它隻進行簡單而機械的字元串替換,而不進行任何檢查。#define不隻是可以為類型取别名,還可以定義常量、變量、編譯開關等。

5)操作符重載

       學習C#時,知道可以對已有操作符進行重組,也就是賦予操作法新的功能。但是在C#中,我們很少這麼做。Java中雖然沒有語言級别的支援,但是Java中字元串拼接使用的+,其實就可以看做是操作符的重載。

       在了解到C++中有操作符重載後,哦,原來這一點,C#是借鑒C++的呀。另外C#中還保留了struct。說到struct,再提一點,struct完全可以了解為C語言中的類。

        C++ 中則使用了大量的操作符重載。具體的怎麼去定義操作符重載,用到的時候再說吧。

  一天半時間,了解的東西真的不多,都是最基本的。雖然我也知道C++中的字元串拼接沒有Java、JavaScript那麼随意那麼任性。但是這些不屬于難點,是以我認為不需要再提了。

  最後,開一個玩笑,不懂JavaScript的Java程式員不是一個好的C++程式員。不懂Java的JavaScript程式員也不是一個好的C++程式員。

作者: 房繼諾

出處:http://www.cnblogs.com/f1194361820

版權:本文版權歸作者和部落格園共有

歡迎轉載,轉載請需要注明部落格出處

技術交流QQ:1194361820,加好友請注明:來自部落格園,不要說你是部落格園,也可以掃描圖像二維碼直接加我。

C++: 主要知識點