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操做符),和链表的内容(这些内容对你们来讲是陌生的)。

这是一个交朋友的程序,你们不妨编译运行一下,看看效果,再尽力把代码搞懂(为了不越界访问,请不要输入得太古怪)。

相关文章
相关标签/搜索