C到C++ 快速過分 C 結構體到類

<!--結構體-->
ios

還記得C語言中的結構體麼?
struct Point{
    double x;
    double y;
};
上面的代碼是一個「結構體模版」,咱們利用它建立了一個叫作Point的類型。

在這以後,咱們就能夠像聲明基本類型的變量同樣聲明Point類型:
Point ob;

ob叫作結構體Point的一個「實例」。(更多被稱爲「對象」,下文中再也不區分「實例」和「對象」這兩個詞。)
數組

而當咱們 int n; 的時候,會講聲明瞭int類型的一個「變量」 n。
安全

而當咱們Point ob; 的時候,咱們通常稱「構建了Point的一個對象」 ob。
函數


結構體是一種複合類型,可是它和一樣身爲複合類型的數組不一樣。spa

數組是相同類型元素的線性集合,而一個結構體中卻能含有不一樣類型的成員。
對象


<!--數組操做技巧-->   // 這是穿插的關於數組經常使用操做的講解  和結構體與類並無多大關係 不感興趣的能夠跳過^_^
內存

char name[20];
咱們這樣就聲明瞭一個數組,而且每一個name[i](0 <=i < 20)都是一個獨立的char類型的變量。它們被稱爲數組的「元素」。

值得一提的是,同一個數組的各個元素所佔用的內存空間是連續的。
ci

這使得咱們在遍歷(檢索)整個數組的時候,速度很是的快:

int line[] = {2, 5, 6, 7, 8, 12, -5, -32};        // 1
int len = sizeof(line) / sizeof(int);            // 2
for(int i = 0; i < len; i++)
    line[i] = -line[i];

上述語句遍歷這個數組,而且將每一個元素的值都取反。

第 1 個語句說明,數組能夠根據你聲明時填寫的數據自動分配大小,可是一旦分配,數組的大小就定了。

第 2 個語句能夠直接肯定數組中元素的個數,這樣就無需一個個數了。
sizeof是一個操做符,用法相似於函數。當參數是數組名時,將獲得整個數組所佔內存的字節數;而當參數是類型時,獲得的是該類型變量的字節數。

而對於字符串數組,初始化有更方便的方法:
作用域

char name[] = "Always Laugh";字符串

這樣name就會被自動分配成長度13的數組(別忘了'\0')。


除了以前介紹的使用sizeof操做符取元素個數的方法之外,頭文件<string.h>(C++中shi<cstring>)中的strlen函數能夠更方便地取字符串長度:

char name[] = "Always Laugh";
int len = strlen(name);
for(int i = 0; i < len; i++)
    name[i]++;

這個代碼會把name數組的的每一個元素在字符表中「後移」一位。

須要注意的是,strlen只能處理char的字符串數組,對int等不適用。

而且它以字符串末尾的'\0'字符爲結束標誌,所以取到的每每不是數組大小。



<!--類-->

如今介紹C++中的「類」這個概念,它和結構體極其類似。

咱們先寫一個使用結構體的程序:

#include <iostream>

using namespace std;

struct Point{                //  1 結構體的模版

    double x;        //  成員變量

    double y;

};

int main()

{

    Point p;                //  2 結構體實例的構建

    p.x = 3.2;                 //  3 結構體實例的使用

    p.y = 8.9;

    cout << "(" << p.x << "," << p.y << ")" << endl;    // 結構體的使用

    return 0;

}

結構體的模版和函數的定義性質相同(以後介紹的「類」也一樣),只是規定了這個類型的內部結構和工做原理,並不分配內存

咱們在使用結構體對象的時候,老是使用它的成員。「.」這個操做符用來鏈接結構體的實例和它的成員。

實例的名稱能夠自由去定義,就像變量名同樣,可是同一個結構體/類的實例老是擁有徹底相同的的成員,都和模版中的一致。

利用相同模版初始化的實例都具備相同的成員


而當將類引入時,會發生較大的變化:

#include <iostream>

using namespace std;

class Point{        // 類模板

private:

    double x;        // 私有成員變量

    double y;        // 私有成員變量

public:

    setPoint(double m, double n){        // 共有成員函數

        x = m; y = n;        // 私有成員變量x y 在同爲成員的函數中出現

    }                               // 而且此時不須要"."做爲成員鏈接符 由於x y 和函數setPoint  都在Point類「內部」


    printPoint(){                                      // 共有成員函數

        cout << "(" << x << "," << y << ")" << endl;        // 同上

    }

};


int main()

{

    Point p;

    p.setPoint(3.2, 8.9);

    p.printPoint();

    return 0;

}


這個程序和用結構體的效果是相同的,可是複雜的地方集中在了類的模版定義部分。

出現了不少陌生的東西,private,public,甚至還有函數。


這是由於,對於類而言,不只變量能夠做爲成員,函數也能夠。

(注意:如今結構體也支持成員函數了 可是這個概念和類更緊密)

而當你想要在主函數中使用以下語句時:

p.x = 2.2; p.y = 1.1;

你會發現這個不容許的。

緣由就在於關鍵字private(私有的),它將x和y成員保護了起來,使它們在「模版區」以外不能出現。

注意是「不能出現」,而不只是「不能賦值」。這意味着 cout << p.x; 也是不容許的。


關鍵字public(公有的)定義的成員能夠暴露給外界,正如主函數中的p.setPoint(3.2, 8.9);和p.printPoint();同樣。


把x和y設置爲私有成員是爲了數據的隱祕性和安全性:

int main()

{

    Point p;

    p.setPoint(3.2, 8.9);

    p.printPoint();

    return 0;

}

這是剛剛的主函數,咱們從中根本看不出p這個類含有哪一種或者多少個私有成員,更不知道成員叫作x/y。這種技巧叫作「信息屏蔽」。

它們確實能夠在類模版中看到,可是在工程中咱們使用的類,大多數是見不到類模版的,他們存放在不一樣的文件中。

這樣,咱們只須要知道類的公有成員函數接受哪些變量,起到哪些做用,學會調用便可。至於具體細節,內部邏輯,咱們不須要知道。

這就是「封裝」,C++的三大特性之一。


正如你看到的,私有成員變量能夠在成員函數中直接出現,由於它們處於同一個做用域中(類模版的花括號)。

有私有成員函數嗎?固然有。它能夠供其餘私有成員函數或者公有成員函數去調用。

總之,只有公有成員(能夠出如今「模版區」以外)纔會和「.」連用。由於一個「實例」的聲明和使用都是在外界的


簡而言之:

成員包括私有成員和公有成員。

成員分爲成員變量和成員函數。



<!--構造函數-->

class Point{

private:

    double x;

    double y;

public:

    Point(){

    }

    

    Point(double m, double n) {

        x = m; y = n;

    }

    

    setPoint(double m, double n){

        x = m; y = n;

    }

    

    printPoint(){

        cout << "(" << x << "," << y << ")" << endl;

    }

};


仍然是那個類,多了兩個比較怪異的函數。沒錯,函數的名稱和類名稱同樣,而且他們不含返回值。

有了它們,咱們即可以在主函數中這樣子聲明p。

int main()

{

    Point p(3.2, 8.9);

    p.printPoint();

    return 0;

}

構造函數是在初始化實例的過程當中調用的,這樣咱們能夠在初始化的同時給成員賦值,而setPoint用來改變成員的值。

爲何Point函數聲明瞭兩次?還記得函數重載麼?咱們重載了它。

這樣咱們既能夠在聲明實例的時候初始化它,也能夠不這麼作。

由於構造函數老是會執行的。Point p;和Point p();絲毫沒有區別。



<!--些許複雜的示例程序-->

#include <iostream>

#include <cstring>

using namespace std;

struct Friend{

    char name[20];

    Friend* nest;


    Friend(char* pn){

        strcpy(name, pn);

        nest = NULL;

    }

};


struct FriendList{

    Friend* head;

    Friend* mov;

    int number;

    bool none;


    FriendList(Friend* pri){

        head = mov = pri;

        number = 1;

        none = 0;

    }

    

    void ReTop(){

        mov = head;

        none = 0;

    }


    void BeFriend(Friend* someone){

        Friend* temp = mov->nest;

        mov->nest = someone;

        someone->nest = temp;

        number++;

    }


    bool Que(Friend *f){

        if(none) {

            cout << "You got no friends.\n\n";

            ReTop();

            return 0;

        }

        if(!mov->nest) none = 1;

        char ch;

        while(getchar() != '\n') continue;

        cout << "Do you wang to make friends with "

            << mov->name << "?" << endl

            << "Y to YES and N to NO" << endl;

        cin >> ch;

        if(ch == 'Y') {

            cout << "You've been friend with " << mov->name << "!\n\n";

            BeFriend(f);

            ReTop();

            return 0;

        }else{

            mov = mov->nest;

            return 1;

        }

    }


    void End()

    {

        Friend* temp;

        while(number--) {

            temp = head->nest;

            delete(head);

            head = temp;

        }

    }

};


int main()

{

    char name[20] = "Always Laugh";

    Friend *Me = new Friend(name);

    FriendList myFriend(Me);

    int T = 4;

    while(T--) {

        cout << "Enter your name: ";

        cin >> name;

        Friend* you = new Friend(name);

        cout << "Hello " << you->name << "!" << endl;

        while(myFriend.Que(you));

    }

    return 0;

}


這個示例程序對剛接觸C++的人來講難度很大,接近一個課設。由於類的內部聯繫複雜。

而且還用到了動態內存分配(好比new和delete操做符),和鏈表的內容(這些內容對你們來講是陌生的)。

這是一個交朋友的程序,你們不妨編譯運行一下,看看效果,再盡力把代碼搞懂(爲了不越界訪問,請不要輸入得太古怪)。

相關文章
相關標籤/搜索