快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

C++面向对象编程入门:类(class)

    结构体的掌握非常重要,重要在哪里呢?重要在结构体和类有相同的特性,但又有很大的区别,类是构成面向对象编程的基础,但它是和结构体有着极其密切的关系。

      我们在c语言中创建一个结构体我们使用如下方法:

    struct test
    {
        private:
            int number;
        public:
            float socre;
    };

      类的创建方式和结构体几乎一样,看如下的代码:

    class test
    {
        private:
            int number;
        public:
            float socre;
        public:
            int rp()
            {
                return number;
            }
            void setnum(int a)
            {
                number=a;
            }
    };

      但是大家注意到没有,标准c中是不允许在结构体中声明函数的,但c++中的类可以,这一点就和c有了本质的区别,很好的体现了c++面向对象的特点!

      过去的c语言是一种非面向对象的语言

      他的特性是:

      程序=算法+数据结构

      但c++的特性是

      对象=算法+数据结构

      程序=对象+对象+对象+对象+........

      所以根据这一特性,我们在定义一个自己定义的结构体变量的时候。这个变量就应该是叫做对象或者叫实例。

      例如

    test a;

      那么a就是test结构的一个对象(实例)

      test结构体内的成员可以叫做是分量,例如:

    a.socre=10.1f;

      那么number就是test结构的对象a的分量(或者叫数据成员,或者叫属性)score;

      在c语言中结构体中的各成员他们的默认存储控制是public 而 c++中类的默认存储控制是private,所以在类中的成员如果需要外部掉用一定要加上关键字public声明成公有类型,这一特性同样使用于类中的成员函数,函数的操作方式和普通函数差别并不大。

      例如上面的例子中的rp()成员函数,我们如果有如下定义:

    test a;

      的话,调用rp()就应该写成:

    a.rp();

      成员函数的调用和普通成员变量的调用方式一致都采用.的操作符。

      这一小节为了巩固联系我给出一个完整的例子。

      如下(重要和特殊的地方都有详细的注解):

    #include <iostream>
    using namespace std;
    class test
    {
        private://私有成员类外不能够直接访问
            int number;
        public://共有成员类外能够直接访问
            float socre;
        public:
            int rp()
            {
                return number;
            }
            void setnum(int a)
            {
                number=a;
            }
    };

    void main()
    {
        test a;
        //a.number=10;//错误的,私有成员不能外部访问
        a.socre=99.9f;
        cout<<a.socre<<endl;//公有成员可以外部访问
        a.setnum(100);//通过公有成员函数setnum()间接对私有成员number进行赋值操作
        cout<<a.rp();//间接返回私有成员number的值
        cin.get();
    }

      好了,介绍了在类内部定义成员函数(方法)的方法,下面我们要介绍一下域区分符(::)的作用了。

      下面我们来看一个例子,利用这个例子中我们要说明两个重要问题:

    #include <iostream>
    using namespace std;
    int pp=0;
    class test
    {
        private:
            int number;
        public:
            float socre;
            int pp;
        public:
            void rp();
    };
    void test::rp()//在外部利用域区分符定义test类的成员函数
    {
        ::pp=11;//变量名前加域区分符给全局变量pp赋值
        pp=100;//设置结构体变量
    }

    void main()
    {
        test a;
             test b;
        a.rp();
        cout<<pp<<endl;
        cout<<a.pp<<endl;

        cin.get();
    }


      问题1:


      利用域区分符我们可以在类定义的外部设置成员函数,但要注意的是,在类的内部必须预先声明:

    void test::rp()

      在函数类型的后面加上类的名称再加上域区分符(::)再加函数名称,利用这样的方法我们就在类的外部建立了一个名为rp的test类大成员函数(方法),可能很多人要问,这么做有意义吗?在类的内部写函数代码不是更好?

      答案是这样的:在类的定义中,一般成员函数的规模一般都比较小,而且一些特殊的语句是不能够使用的,而且一般会被自动的设置成为inline(内联)函数,即使你没有明确的声明为inline,那么为什么有会被自动设置成为inline呢?因为大多数情况下,类的定义一般是放在头文件中的,在编译的时候这些函数的定义也随之进入头文件,这样就会导致被多次编译,如果是inline的情况,函数定义在调用处扩展,就避免了重复编译的问题,而且把大量的成员函数都放在类中使用起来也十分不方便,为了避免这种情况的发生,所以c++是允许在外部定义类的成员函数(方法)的,将类定义和其它成员函数定义分开,是面向对象编程的通常做法,我们把类的定义在这里也就是头文件了看作是类的外部接口,类的成员函数的定义看成是类的内部实现。写程序的时候只需要外部接口也就是头文件即可,这一特点和我们使用标准库函数的道理是一致的,因为在类的定义中,已经包含了成员函数(方法)的声明。

      问题二

      域区分符和外部全局变量和类成员变量之间的关系。

      在上面的代码中我们看到了,外部全局和类内部都有一个叫做pp的整形变量,那么我们要区分操作他们用什么方法呢?

      使用域区分符就可以做到这一点,在上面的代码中::pp=11;操作的就是外部的同名称全局变量,pp=100;操作的就是类内部的成员变量,这一点十分重要!

      问题三

      一个类的所有对象调用的都是同一段代码,那么操作成员变量的时候计算机有是如何知道哪个成员是属于哪个对象的呢?

      这里牵扯到一个隐藏的this指针的问题,上面的代码在调用a.rp()的的时候,系统自动传递一了个a对象的指针给函数,在内部的时候pp=100;的时候其实就是this->pp=100;

      所以你把上面的成员函数写成如下形势也是正确的:

    void test::rp()
    {
        ::pp=11;
        this->pp=100;//this指针就是指向a对象的指针
    }

      类的成员函数和普通函数一样是可以进行重载操作的,关于重载函数前面已经说过,这里不再说明。

      给出例子仔细看:

    #include <iostream>
    using namespace std;
    class test
    {
        private:
            int number;
        public:
            float socre;
            int pp;
        public:
            void rp(int);
            void rp(float);
    };
    void test::rp(int a)//在外部利用域区分符定义test类的成员函数
    {
        cout<<"调用成员函数!a:"<<a<<endl;
    }
    void test::rp(float a)//在外部利用域区分符定义test类的成员函数
    {
        cout<<"调用成员函数!a:"<<a<<endl;
    }
    void main()
    {
        test a;
        a.rp(100);
        a.rp(3.14f);
        cin.get();
    }


 

      下面我们来看一下利用指针和利用引用间接调用类的成员函数,对于对于指针和引用调用成员函数和调用普通函数差别不大,在这里也就不再重复说明了,注意看代码,多试多练习既可。

      代码如下:

    #include <iostream>
    using namespace std;
    class test
    {
        private:
            int number;
        public:
            float socre;
            int pp;
        public:
            int rp(int);
    };
    int test::rp(int a)//在外部利用域区分符定义test类的成员函数
    {
        number=100;
        return a + number;
    }

    void run(test *p)//利用指针调用
    {
        cout<<p->rp(100)<<endl;
    }
    void run(test &p)//利用引用
    {
        cout<<p.rp(200)<<endl;
    }

    void main()
    {
        test a;
        run(&a);
        run(a);
        cin.get();
    }

      前面我们说过,类的成员如果不显式的生命为public那么它默认的就是private就是私有的,私有声明可以保护成员不能够被外部访问,但在c++还有一个修饰符,它具有和private相似的性能,它就是protected修饰符。

      在这里我们简单说明一下,他们三着之间的差别:

      在类的private:节中声明的成员(无论数据成员或是成员函数)仅仅能被类的成员函数和友元访问。
      在类的protected: 节中声明的成员(无论数据成员或是成员函数)仅仅能被类的成员函数,友元以及子类的成员函数和友元访问。
      在类的public:节中声明的成员(无论数据成员或是成员函数)能被任何人访问。

      由于private和protected的差别主要是体现在类的继承中,现在的教程还没有设计到友元和子类所以这里不做深入讨论,但上面的三点务必记得,在以后的教程中我们会回过头来说明的。

      总的来说,类成员的保护无非是为了以下四点!

      1.相对与普通函数和其它类的成员函数来说,保护类的数据不能够被肆意的篡改侵犯!

      2.使类对它本身的内部数据维护负责,只有类自己才能够访问自己的保护数据!

      3.限制类的外部接口,把一个类分成公有的和受保护的两部分,对于使用者来说它只要会用就可以,无须了解内部完整结构,起到黑盒的效果。

      4.减少类与其它代码的关联程,类的功能是独立的,不需要依靠应用程序的运行环境,这个程序可以用它,另外一个也可以用它,使得你可以轻易的用一个类替换另一个类。


      下面为了演示类成员的保护特性,我们来做一个球类游戏!

      我们设计一个类,来计算球员的平均成绩,要求在外部不能够随意篡改球员的平均成绩。

      我们把该类命名为ballscore并且把它放到ballscore.h的有文件中!

    class ballscore
    {
        protected:
            const static int gbs = 5;  //好球单位得分
            const static int bbs = -3;  //坏球单位扣分
            float gradescore;  //平均成绩
        public:
            float GetGS(float goodball,float badball)  //goodball为好球数量,badball为坏求数量
            {

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论