精华内容
下载资源
问答
  • java面向对象中属性和方法的封装

    千次阅读 2016-05-04 21:59:34
    java的封装在对其成员变量的体现,是对其访问权限的设置,通过修饰符private (私有的),public(共有的),protected(受保护的),还有默认的友好型的。  用关键字private修饰的成员变量称为私有变量,例如:  class...

    java的封装在对其成员变量的体现,是对其访问权限的设置,通过修饰符private (私有的),public(共有的),protected(受保护的),还有默认的友好型的。

            用关键字private修饰的成员变量称为私有变量,例如:

        class Tom{

        private float weigh;

        private float f(float a,float b){

            return a + b;

        }

    }

        当另一个类中用Tom重建一个对象时,该对象不能访问自己的私有变量和方法,

        class Jerry{

            void g(){

                Tom cat = new Tom();

                cat.weight=2.3f;    //非法

                float sum=cat.f(3,4)    //非法

        }

    }

        但可以通过在类中创建set()和get()方法,来实现对其变量的赋值和方法的调用,例如将上诉的Tom类改为:

        class Tom{

        private float weigh;

        private float f(float a,float b){

            return a + b;

        }

        public float setWeight(float weigh){

            this.weight=weight;

            return weight;

        }

        

        private float setF(float a,float b){

            f( a, b);

            return a+b;

        }

    }

        那么类Jerry中的Tom的实例化对象通过setWeight()和setF()便可以赋值和调用方法了,内容如下

        

    class Jerry{

            void g(){

                Tom cat = new Tom();

                cat.setWeight(2.3f);    //合法

                cat.weight=2.3f;    //非法

                float sum=cat.setF(3,4);    合法

                float sum=cat.f(3,4)    //非法

        }

    }

        java的面向过程中封装、继承、多态是相互关联且不可分的,今天就简单的说下封装中关于成员变量和方法的自己的认识吧,还想写一些其他的吧,下一篇写下封装中关于对对象的封装,通过怎么显示出一个类实例化的对象的个数和如何实现只实例化出一个对象的例子说下自己的理解吧。

    展开全文
  • 对象属性、方法、 封装与继承

    千次阅读 2017-10-03 22:09:40
    对象:用来描述客观事物的一个实体,又一组属性和方法构成 属性对象具有的各种特征,每个对象的每个属性都拥有特定值 ...是模子,确定对象将会拥有的特征(属性和行为(方法) 面向对象设计提抽象的过程
    对象:用来描述客观事物的一个实体,又一组属性和方法构成
    属性:对象具有的各种特征,每个对象的每个属性都拥有特定值
    方法:对象执行的操作

    抽象方法 abstract:
    抽象方法没有方法体
    抽象方法必须在抽象类里
    抽象方法必须在子类中被实现除非子类是
    例:

    类图详解: 如图

    类的产出
    从对象中归纳、抽象出类
    根据"对象"抽象出"类"

    具有相同属性和方法的一组对象的集合
    类是模子,确定对象将会拥有的特征(属性)和行为(方法)


    面向对象设计提抽象的过程
    用类图描述设计
    设计的过程
    发现类
    发现类的属性
    发现类的方法
    优化设计
    抽象的原则
    系统所关注的属性
    系统锁关注的方法

    面向对象三大特征之一 : 封装
    封装的基本概念

    封装:
    将类的某些信息隐藏在类的内部,不允许外部程序直接访问,
    而是通过该类提供的方法来实现对隐藏信息的操作和访问。
    封装的好处:
    只能通过规定方法访问数据
    隐藏类的实现细节
    方便加入控制语句
    方便修改实现

    面向对象三大特征之一 : 继承
    继承 如图:

    注意 :子类访问父类成员 使用super关键字 super代表父类对象

    继承后的初始化顺序
    父类属性→父类代码块→父类构造方法→子类属性→子类代码块→子类构造方法

    继承何时使用?
    继承与真实世界类似
    符合is-a关系的设计使用继承
    继承是代码重用的一种方式
    将子类都有的属性和行为放到父类中

    注意:
    有些父类成员不能继承如下!
    1.子类不能访问父类private成员。
    2.子类与父类不再同包,使用默认访问权限的成员
    3.构造方法

















    展开全文
  • c++类和类封装对象线程封装

    千次阅读 2017-07-30 09:18:02
    OOP提供了设计对象的功能,对象包括特性和行为,两者都囊括一起,共同构成对象实体(即实体); 对象实体,使程序更模块化,更易读易写,提升了代码重用到一个更高的层次; 对象提供了对数据操作的直接

    1. C++面向对象编程介绍

    面向对象编程(Object Oriented Programming),简称OOP

    传统的面向过程编程中,数据以及数据的相关操作函数都是分离的独立个体

    对象,如周围的一切其实都是对象;就编程角度,对象包括A)一系列属性(数据);B)一系列操作(函数)。

    OOP提供了设计对象的功能,对象包括特性和行为,两者都囊括在一起,共同构成对象实体(即类实体)

    对象实体,使程序更模块化更易读易写,提升了代码重用到一个更高的层次;

    对象提供了对数据操作的直接方法,定义了如何与对象进行交互,以及对象之间的交互

    更重要的是,OOP提供了更实用的概念:封装、继承、多态和抽象

    这篇主要讲述封装,即对象将数据及其操作函数封装到一个类实体中。

    2. 类和类成员

    C++提供了如char、int、long、float、double等基本数据类型,足够用来解决大多数哦相对简单的问题,但对于复杂的问题就比较困难了。

    C++的一个实用特性是自定义数据类型;如之前的枚举和结构体:


    枚举和结构体代表了传统的面向过程编程,它们只包含数据,如果需要访问此类型变量,必须提供自定义函数,并以该类型变量为参数:


    在OOP世界中,我们希望自己的类型不仅包括数据,也包括操作数据的函数;C++中,通过class关键字来声明一个类。

    2)类类似结构体,但它更多功能和更灵活:


    类似结构体,类的声明没有分配内存,只是说明了类的结构;类的声明以分号结尾

    为了使用类,可以声明一个该类型的变量:


    声明一个类的变量,也叫实例化一个类;该变量称作为类的一个实例,或者对象。

    3)成员函数:

    类不仅仅包含数据(成员变量),亦可以包含函数,称作成员函数


    成员函数可以类似访问成员变量,使用'.'来使用:


    通常,类的成员变量,加一个前缀'm_'来区分:

    3. 公有和私有

    1)访问标识符:公有-public关键字,私有-private关键字

    在上面的DateStruct的结构体,它的成员可以在main函数中访问,因为结构体的所有成员默认是公有的,即public;

    公有成员在结构体和类中,程序的任何函数都可以访问;

    但如果Date的成员没有public标识符,则会出现错误:



    这个说明,类成员的默认是私有的,即private的;

    私有的成员只能在类的定义之内的函数可以访问

    可以通过public关键字使成员变为公有的,即可访问了:


    类和结构体的本质区别之一是类的成员可以使用标识符来控制它们的可访问性;

    C++提供了3种不同的访问标识符:public、private、protect,分别是公有的、私有的和保护的:


    4. 访问函数和封装

    1)访问函数,也叫做读写函数;是读取和写入私有成员变量的值。

    例如:


    GetLength函数就是个访问函数。

    访问函数有2种,即getter和setter:


    将数据成员私有化,提供Getter和Setter来访问,即所谓的"封装" ;

    2)封装

    封装的思想就是将实现的细节隐藏,而暴露公有接口;

    C++中的访问标识符,可以实现在类中的封装;通常是将所有的成员变量私有化;

    尽管看起来访问成员变量的不直接,但使程序更有可重用性和可维护性;

    A)封装实现,无论类的实现如何改变,只要对外的接口不发生变化即可。


    如图上例,如果m_Value被重命名了,那么main函数中访问就会出错;

    如果提供了m_Value的访问函数:


    B)隐藏了类的实现,类的使用者只需知道公共的接口,就可以使用该类;

    C)封装帮助防止意外的改变和误用;

    D)对程序调试有很大的帮助,因为改变类的成员变量只用通过公共接口。

    5. 构造函数Ⅰ

    1)构造函数:是类的一种特殊的成员函数,当类被实例化时执行;通常用以初始化成员变量。

    构造函数有明确的命名规则:A)函数名必须和类名一样;B)无返回类型(包括void)。

    无参构造函数-不带参数的构造函数,是类的默认构造函数:


    通常,类都包含一个默认的构造函数,可以初始化成员变量。

    含参构造函数-含有参数的构造函数,可以对成员变量赋予指定的值;


    以上的两个构造函数,类似重载函数;构造函数必须有唯一的前面(参数个数和参数类型)。

    类亦可以只提供含参构造函数,没有默认构造函数:



    6. 析构函数

    析构函数是类的另一种特殊的函数,当类的对象销毁时调用;它和构造函数是成对出现的。

    普通的简单类,一般不需要析构函数;因为C++会自动回收垃圾;

    如果类中执行了某些动态内存分配,则需要显式定义析构函数,并释放回收垃圾;

    析构函数的明确命名规则:A)函数名和类名一样,并前缀'~';B)不能带参数(即意味着只有一个析构函数);C)没有返回类型。



    注意动态分配,必须提供析构函数,来回收分配的空间。

    2)构造函数和析构函数的时序:


    如上图所示,输出的依次是:simple的构造函数,pSimple的构造函数,最后是pSimple的析构函数。

    构造函数和析构函数的时序是:Constructor First, Destructor Last。

    7. 隐藏的'this'指针

    如之前的例子中的this,是每个类的成员函数隐藏的指针,它指向了类成员函数打交道的类的对象。

    实用性:

    1)当构造函数或成员函数中的参数名和成员变量名相同时,可以使用this来访问本类的成员变量;

    2)可以使用this返回类的对象引用:


    8. 构造函数Ⅱ

    1)私有构造函数-如果不想类以外使用指定的构造函数,我们可以将它私有化。


    类只能被实例化一次,称作为单一性;通常使用私有/保护构造函数进行的。

    2)构造函数链和初始化

    有时,一个构造函数所做的工作和另外的构造函数一样,只是增加了一些;

    这样这个构造函数可以调用另外的构造函数,称作为构造函数链。如C#就支持这种格式,但C++不支持。

    但构造函数可以调用类中的非构造函数,只是要注意这些非构造函数调用的成员,必须已经初始化。

    通常的做法就是,定义一个公共的非构造函数,构造函数都调用它来初始化共同的;例如:


    9. 类代码和头文件

    1)在类的定义之外定义成员函数。

    如之前的类定义,都是在类的定义中定义成员函数:


    当类的定义越来越长和越来越复杂时,就显得臃肿,难以维护和操作;

    幸运的是,C++提供了一种分离类的定义及其应用定义的方法,将类的成员函数在类的外面定义;格式是:类名::函数名


    2)将类的定义放在头文件中:

    头文件的使用可达到重用的效果;所以将类的定义放在头文件中,而成员函数放在.cpp中定义;而cpp的名字需和类的名字相同。

    Date.h:


    Date.cpp:


    推荐分离类的定义中的成员函数到类外定义。

    10. 常量类对象和成员函数

    函数的参数可以为常量对象,如内置的基本数据类型一样,类对象也可以声明为常量,所有常量对象的变量必须在创建时初始化,其后不能修改。



    上图3个错误,因为程序试图修改常量类对象的变量;


    因为常量类对象不能调用非常量成员函数;

    常量成员函数-保证不修改任何类变量或调用任何非常量函数。

    为了使GetValue常量化,可以在其原型加个const关键字:


    注意:

    A) 常量成员函数在类外定义时,也必须加const关键字;

    B) 任何常量成员函数试图修改类成员变量,或者调用非常量成员函数都是非法的,会产生编译错误。

    C)构造函数不能常量化;

    重载函数使用const和非const,是当返回类型不一样的时候。

    11. 静态成员变量

    在之前的程序中,静态表示变量的值在运行期间保持最新的值;

    1)静态成员变量

    在实例化两个对象,其包含的相同的成员变量;

    静态成员变量是属于类的本身,是所有对象的共享变量;它的值是保持修改的最新值;

    使用格式:类名::静态成员。

    2)静态成员变量的初始化

    初始化必须在类的代码文件中进行。

    12. 静态成员函数

    如静态成员变量一样,静态成员函数是属于类的本身,不属于任何类的对象;

    如静态成员变量访问一样,可以通过:类名::静态成员来访问类的静态成员变量。

    注意:静态成员函数,没有this指针;

    例如:


    13. 友元类和友元函数

    多数时候,类和函数需要运行很紧密;但需使用显示函数来打印相关信息,这并不显得很隐藏类的细节;

    这时,友元类很友元函数就很好的访问私有细节;

    1)友元函数

    友元函数访问类的私有成员,就如其是类的一个成员函数。

    一个友元函数可以是,也可以不是其他类的成员函数;使用关键字friend。

    例如:


    一个友元函数可以是多个类的友元函数;

    2)友元类

    友元类是,声明在其他类中,可以访问其他类的私有变量;


    在使用友元函数和友元类时,请务必谨慎。

    14. 匿名变量和对象

    所谓匿名,就是可以不通过命名变量来访问,减少临时变量。


    【免责特此声明:
    1)本内容可能是来自互联网的,或经过本人整理的,仅仅代表了互联网和个人的意见和看法!
    2)本内容仅仅提供参考,任何参考该内容造成任何的后果,均与原创作者和本博客作者无关!】









    C++学习:类,对象,封装

    1. 对象
    2. 封装

      C++是一门集面向过程,面向对象以及泛型编程于一体的强大的编程语言,在这里面最重要的要属面向对象了吧???什么是面向对象?面向对象的思想是什么???总结下来就一句话:万物皆对象.在面向对象的世界里,一切都是可以用对象来解释的.这也是面向对象思想的精髓部分.

      万物皆对象

      1:类

      举个例子:在超时里面进行商品购物的时候,它所有的商品都是按类目来划分的.生活用品,食品等.这就是按类别来分.而在自然界中也是.如:动物昆虫等.这就是类.将一类相似的的东西抽象成一类东西.

    结构化程序设计

        程序 = 算法 +数据结构
    

    面向对象设计OOP

        OBJECT ORIENRED PROGRAMING
        Object oritened programing
        程序 = 对象 +对象 +....
        关键:让每个对象都负责执行一组相关的任务
    

    面向对象开发范式的特性:

        万物皆是对象
        程序是一组对象彼此之间在发送消息
        每个对象都有自己的内存占用,可以组装成更大的对象
        每个对象都有类型,特定类型的对象都可以接收相同的消息
    

    概念:

    类:类是创建对象的模板和蓝图,类是一组相似对象的共同抽象定义
    对象:对象是类的实例化结果,对象是实实在在的存在,代表现实世界的某一事物
    

    对象的三大特性:

        行为:对象能干什么
        状态:对象的属性,行为的结果
        标识:对象的唯一身份;
    

    类和对象的区别:

        类是静态定义
        对象是动态实例
        建立模型得到的是类而非对象
    

    联系:

        类是对象的定义
        对象的产生离不开类这个模板
        类存在的摸底是实例化得到对象
    

    世界是由对象组成的

    定义一个类的步骤: 
    1:定义类名 
    2:编写类的数据成员代表属性 
    3:编写类的方法代表行为

    类的建模是一个抽象和封装的过程: 
    抽象:去掉不关注的,次要的信息而保留重要的信息 
    封装:信息打包 
    具体一点:将数据和行为结合在一个包中,对对象的使用者隐藏数据的具体实现方式 
    实现封装的关键:不能让类中的方法直接访问其他类的内部数据,只能通过公开行为方法间接访问:

            例子:
    
                class ClassName{
                    field1;
                    field2;
                    .....;
                    constructor;
                    .....
                    method1;
                    method2;
                }
    

    对象的两种类的形式:

        1:结构体形式:
        struct Saving{
            unsigned accountNumber;
            float balance;
        };
      缺点:安全性不好,任何人都是可以进行访问的     
    
        2:class形式:
        class Savings{
            public:
                float deposit(float amount){
                    balance +=amount;
                    return balance;
                }
            private:
                unsigned accountNumber;
                float balance;
        };
        优点:类不仅可以保护数据,而且可以提供成员函数来操作
    

    C++用类来定义抽象数据类型

    C++早期的版本被成为带类的C

    class 类名称{
        public:
            //共有函数
        protected:
            //保护成员
        private:
            //私有函数
            //私有成员
            int val;
    };
    

    类中定义成员函数:

    class Tdate{
        public:
            void set(int m = 1,int d = 2,int y = 3){
                month = m;
                day = d;
                year = y;
            }
            bool isLeepYear(){
                return (year%4 ==0  &&year%100!=0) || (year %400==0);
            }
            void print(){
                cout<<year<<"/"<<month<<"/"<<day<<endl;
            }
        private:
            int month,day,year;
    }
    
    调用:
        int main(){
            Tdate d;
            d.set(2,4,1998);
            d.print();
        }
    

    在类中定义成员函数: 
    类中定义的成员函数一般都为内联函数,即使没有明确用inline标示 
    在C++中,类定义通常在头文件中,因此这些成员函数定义也伴随这进入头文件

    在类之后定义成员函数: 
    C++允许在其他地方定义成员函数; 
    将类定义和其成员函数定义分开,是目前开发程序的通常做法 
    我们把类定义看成是类的外部接口,类的成员函数定义看成是类的内部实现

    看一个最简单的实例:在main.cpp中去定义一个类.并且在此类中直接实现成员函数.(也可以通过Car.h和Car.cpp的形式去实现)

    /*
     * ===========================================================================
     *
     *       Filename:  main.cpp
     *    Description:  
     *        Version:  1.0
     *        Created:  2017年05月26日 22时24分05秒
     *       Revision:  none
     *       Compiler:  gcc
     *         Author:   (), 
     *        Company:  
     *
     * ===========================================================================
     */
    
    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    using namespace::std;
    
    class Car{
      public:
        void run(){
          cout <<"car run"<<endl;
        }
    
        void shut(){
          cout<<"car shutdown"<<endl;
        }
    
        void setProperty(int price,int carNum){
          this->mPrice = price;
          this->mCarNum = carNum;
        }
    
      private:
         int mPrice;
         int mCarNum;
    };
    
    int main(int argc,char *argv[]){
      Car mCar;
      /* *类的成员函数是不会占用内存的 */
      cout <<"sizeof Car" <<sizeof(mCar)<<endl;
      cout << &mCar <<endl;
      mCar.setProperty(10000,1000000);
      mCar.run();
      mCar.shut();
    
      return 0;
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    通过Car.cpp及Car.h来实现一个简单类的封装

    /*
     * ===========================================================================
     *
     *       Filename:  Car.h
     *    Description:  
     *        Version:  1.0
     *        Created:  2017年05月26日 22时43分53秒
     *       Revision:  none
     *       Compiler:  gcc
     *         Author:   (), 
     *        Company:  
     *
     * ===========================================================================
     */
    
    #ifndef __CAR_H__
    #define __CAR_H__
    
    #ifdef __cplusplus
    extern "C"{
    #endif
    
    /* *
     * 在头文件中去定义一个Car类型
     * */
    class Car{
      private:
        int mCarPrice;
        int mCarNum;
        int mCarType;
      public:
        void run();
        void shut();
        void setProperty(int price,int carNum,int carType);
        void print();
    };
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    /*
     * ===========================================================================
     *
     *       Filename:  Car.cpp
     *    
     *        Version:  1.0
     *        Created:  2017年05月26日 22时48分41秒
     *       Revision:  none
     *       Compiler:  gcc
     *         Author:   (), 
     *        Company:  
     *
     * ===========================================================================
     */
    
    #include<iostream>
    using namespace::std;
    
    /**
     * 包含Car头文件
     */
    #include<Car.h>
    
    /* *
     *类的行为的实现,定义
     * */
    void Car::run(){
      cout << "car run" << endl;
    }
    
    void Car::shut(){
      cout << "car shut" << endl;
    }
    
    void Car::setProperty(int price,int carnum,int cartype){
      mCarPrice = price;
      mCarNum = carnum;
      mCarType = cartype;
      if(mCarType == 1){
        cout << "car type is one" <<endl;
      }else if(mCarType == 2){
        cout << "car type is two" <<endl;
      }else if(mCarType == 3){
        cout << "car type is three" <<endl;
      }
    }
    
    void Car::print(){
      cout <<"price:"<<mCarPrice<<"\n";
      cout <<"carnum:"<<mCarNum<<"\n";
      cout <<"carType"<<mCarType<<endl;
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    /*
     * ===========================================================================
     *
     *       Filename:  CarTest.cpp
     *    Description:  
     *        Version:  1.0
     *        Created:  2017年05月26日 23时18分01秒
     *       Revision:  none
     *       Compiler:  gcc
     *         Author:   (), 
     *        Company:  
     *
     * ===========================================================================
     */
    
    #include<iostream>
    using namespace::std;
    
    #include<Car.h>
    /* *
     *使用指针的方式来调用成员函数,类似结构体指针调用成员变量
     * */
    void usePoint(Car *mCar){
      cout<<"==============="<<endl;
      mCar ->setProperty(20000,20002,3);
      mCar ->run();
      mCar ->shut();
      mCar ->print();
    }
    
    
    /* *
     *使用引用的形式来调用成员函数,与对象的调用一致
     * */
    void userReference(Car &mCar){
      cout << "==============="<<endl;
      mCar.setProperty(10000,100001,2);
      mCar.run();
      mCar.shut();
      mCar.print();
    }
    
    
    int main(int argc,char *argv[]){
      Car mCar;
      cout << "address:"<< &mCar <<endl;
      cout <<"size of mCar"<< sizeof(mCar) <<endl;
      mCar.setProperty(80001,88888,1);
      mCar.run();
      mCar.shut();
    
      usePoint(&mCar);
      userReference(mCar);
    
      return 0;
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    以上是简单的关于类和对象以及一个简单的封装的国政

    在成员函数中访问成员:

    成员函数必须用对象来调用
        Car mCar;
        mCar.run();
    在成员函数内部,访问数据成员或成员函数无需如此
        void setProperty(int price,int carNum){
          this->mPrice = price;
          this->mCarNum = carNum;
        }
    

    this指针代表当前对象占用内存空间的地址:

    void Tdate::set(int m ,int d,int y){
        this->month = m;
        this->day = d;
        this->year = y;
    }
    

    通过指针来调用成员函数:

    例子:
        #include"tdate.h"
        #include<iostream>
        void func(Tdate *pDate){
            pDate->print();
            if(pDate->isLeepYear()){
                cout<<"leepyear"<<endl;
            }else{
                cout<<"not leepyear"<<endl;
            }
        }
    

    通过引用来调用成员函数:

    #include"tdate.h"
    #include<iostream>
    void func(Tdate &pDate){
            pDate.print();
            if(pDate.isLeepYear()){
                cout<<"leepyear"<<endl;
            }else{
                cout<<"not leepyear"<<endl;
            }
        }
    

    类的成员函数的重载: 
    类的成员函数可以像普通函数一样进行重载 
    但是不同的类即使有相同的函数名也不算重载

    类的成员函数可以默认设置成员参数: 
    在类之外去定义这样一个类的行为

    OOP三大特性(面向对象的三个特性): 
    继承(inheritance): 
    多态(polymorphism): 
    封装(encapsulation):类背后隐藏的思想是数据抽象和封装 
    信息隐藏,隐藏对象的实现细节,不让外部直接访问 
    将数据成员和成员函数一起包装到 一个单元中 ,单元以类的形式实现 
    将数据成员和成员函数包装进类中,加上具体实现的隐藏,共同被称作封装,其结果是一个同时带有特征和行为的数据类型 
    封装类:定义类,定义其成员函数的过程称为封装类

    细节:

        除非必须公开底层的实现细节,否则应该将所有字段指定为private
        使数据成员私有,控制数据访问限制.增强了类的可维护性
        隐藏方法的具体实现.向外部提供公开的接口.以供安全调用
    

    信息隐藏是OOP最重要的特性之一,也是可以使用访问修饰符的原因 
    访问修饰符号:

        public 
        protected
        private
    

    信息隐藏的原因: 
    对模块的任何实现细节所做的更改不会影响使用该模块的代码 
    防止用户意外的修改数据 
    使模块易于使用和维护







    C++类(Class)总结
     
    一、C++类的定义
        C++中使用关键字 class 来定义类, 其基本形式如下:
    class 类名
    {
    public:
    protected:
    //行为或属性
    private:
    //行为或属性
    };
     
    示例:
         定义一个点(Point)类, 具有以下属性和方法:
         ■ 属性: x坐标, y坐标
         ■ 方法: 1.设置x,y的坐标值; 2.输出坐标的信息。
    实现代码:
    class Point
    {
    public:
         void setPoint(int x, int y);
         void printPoint();
     
    private:
         int xPos;
         int yPos;
    };  
    代码说明:
         上段代码中定义了一个名为 Point 的类, 具有两个私密属性, int型的xPos和yPos, 分别用来表示x点和y点。
         在方法上, setPoint 用来设置属性, 也就是 xPos 和 yPos 的值; printPoint 用来输出点的信息。    

    1 数据抽象和封装
         抽象是通过特定的实例抽取共同特征以后形成概念的过程。一个对象是现实世界中一个实体的抽象,一个类是一组对象的抽象。
         封装
    是将相关的概念组成一个单元,然后通过一个名称来引用它。面向对象封装是将数据和基于数据的操作封装成一个整体对象,对数据的访问或修改只能通过对象对外提供的接口进行。
     
    2 类定义
         几个重要名词:
    (1) 类名
         遵循一般的命名规则; 字母,数字和下划线组合,不要以数字开头。
    (2) 类成员
         类可以没有成员,也可以定义多个成员。成员可以是数据、函数或类型别名。所有的成员都必须在类的内部声明。
         没有成员的类是空类,空类也占用空间。
    class People
    {
    };
    sizeof(
    People) = 1;    
    (3) 构造函数
         构造函数是一个特殊的、与类同名的成员函数,用于给每个数据成员设置适当的初始值。
    (4) 成员函数
         成员函数必须在类内部声明,可以在类内部定义,也可以在类外部定义。如果在类内部定义,就默认是内联函数。
     
    3 类定义补充
    3.1 可使用类型别名来简化类
         除了定义数据和函数成员之外,类还可以定义自己的局部类型名字。
         使用类型别名有很多好处,它让复杂的类型名字变得简单明了、易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的。
    class People
    public: 
         typedef std::string phonenum//电话号码类型
     
         phonenum phonePub; //公开号码
    private:      
         phonenum phonePri;//私人号码
    }; 
     
    3.2 成员函数可被重载
         可以有多个重载成员函数,个数不限。
    3.3 内联函数
         有三种:
    (1)直接在类内部定义。
    (2)在类内部声明,加上inline关键字,在类外部定义。
    (3)在类内部声明,在类外部定义,同时加上inline关键字。
    注意:此种情况下,内联函数的定义通常应该放在类定义的同一头文件中,而不是在源文件中。这是为了保证内联函数的定义在调用该函数的每个源文件中是可见的。
    3.4 访问限制
         public,private,protected 为属性/方法限制的关键字。
    3.5 类的数据成员中不能使用 auto、extern和register等进行修饰, 也不能在定义时进行初始化
         如 int xPos = 0; //错;
    例外:
              静态常量整型(包括char,bool)数据成员可以直接在类的定义体中进行初始化,例如:
              static const int ia= 30; 
     
    4 类声明与类定义
    4.1 类声明(declare)
    class Screen;
          在声明之后,定义之前,只知道Screen是一个类名,但不知道包含哪些成员。只能以有限方式使用它,不能定义该类型的对象,只能用于定义指向该类型的指针或引用,声明(不是定义)使用该类型作为形参类型或返回类型的函数。
    void Test1(Screen& a){};
    void Test1(Screen* a){};
    4.2 类定义(define)
         在创建类的对象之前,必须完整的定义该类,而不只是声明类。所以,类不能具有自身类型的数据成员,但可以包含指向本类的指针或引用。
    class LinkScreen
    {
    public:
              Screen window;
              LinkScreen* next;
              LinkScreen* prev;
    };
     //注意,分号不能丢
         因为在类定义之后可以接一个对象定义列表,可类比内置类型,定义必须以分号结束:
    class LinkScreen{ /* ... */ };
    class LinkScreen{ /* ... */ } scr1,scr2; 
         
    5 类对象
         定义类对象时,将为其分配存储空间。
         Sales_item item; //编译器分配了足以容纳一个 Sales_item 对象的存储空间。item 指的就是那个存储空间。
     
    6 隐含的 this 指针 
         成员函数具有一个附加的隐含形参,即 this指针,它由编译器隐含地定义。成员函数的函数体可以显式使用 this 指针。
    6.1 何时使用 this 指针
         当我们需要将一个对象作为整体引用而不是引用对象的一个成员时。最常见的情况是在这样的函数中使用 this:该函数返回对调用该函数的对象的引用。
    class Screen 
    {
    ...
    public:
          Screen& set(char);
    };
    Screen& Screen::set(char c) 
    {
          contents[cursor] = c;
          return *this;
    }

    7 类作用域
         每个类都定义了自己的作用域和唯一的类型。
         类的作用域包括:类的内部(花括号之内), 定义在类外部的成员函数的参数表(小括号之内)和函数体(花括号之内)。
    class Screen 
    //类的内部
    ...
    }; 
    //类的外部
    char Screen::get(index r, index c) const
    {
         index row = r * width;      // compute the row location
         return contents[row + c];   // offset by c to fetch specified character

         注意:成员函数的返回类型不一定在类作用域中。可通过 类名::来判断是否是类的作用域,::之前不属于类的作用域,::之后属于类的作用域。例如
    Screen:: 之前的返回类型就不在类的作用域,Screen:: 之后的函数名开始到函数体都是类的作用域。
    class Screen 
    public: 
         typedef std::string::size_type index; 
         index get_cursor() const; 
    }; 
    Screen::index Screen::get_cursor() const   //注意:index前面的Screen不能少
         return cursor; 
         该函数的返回类型是 index,这是在 Screen 类内部定义的一个类型名。在类作用域之外使用,必须用完全限定的类型名 Screen::index 来指定所需要的 index 是在类 Screen 中定义的名字。
     
     
    二 构造函数
         构造函数是特殊的成员函数,用来保证每个对象的数据成员具有合适的初始值。
         构造函数名字与类名相同,不能指定返回类型(也不能定义返回类型为void),可以有0-n个形参。
         在创建类的对象时,编译器就运行一个构造函数。
     
    1 构造函数可以重载
         可以为一个类声明的构造函数的数量没有限制,只要每个构造函数的形参表是唯一的。
    class Sales_item;
    {
    public: 
         Sales_item(const std::string&); 
         Sales_item(std::istream&); 
         Sales_item(); //默认构造函数
    }; 
     
    2 构造函数自动执行 
         只要创建该类型的一个对象,编译器就运行一个构造函数:
    Sales_item item1("0-201-54848-8");
    Sales_item *p = new Sales_item(); 

         第一种情况下,运行接受一个 string 实参的构造函数,来初始化变量item1。
         第二种情况下,动态分配一个新的 Sales_item 对象,通过运行默认构造函数初始化该对象。
     
    3 构造函数初始化式
         与其他函数一样,构造函数具有名字、形参表和函数体。
         与其他函数不同的是,构造函数可以包含一个构造函数初始化列表:  
    Sales_item::Sales_item(const string &book): isbn(book), units_sold(0), revenue(0.0)
    { } 
         构造函数初始化列表以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个数据成员后面跟一个放在圆括号中的初始化式。
         构造函数可以定义在类的内部或外部。构造函数初始化只在构造函数的定义中指定。
         构造函数分两个阶段执行:(1)初始化阶段;(2)普通的计算阶段。初始化列表属于初始化阶段(1),构造函数函数体中的所有语句属于计算阶段(2)。
         初始化列表比构造函数体先执行。不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化。
    3.1 哪种类需要初始化式
         const 对象或引用类型的对象,可以初始化,但不能对它们赋值,而且在开始执行构造函数的函数体之前要完成初始化。
         初始化 const 或引用类型数据成员的唯一机会是构造函数初始化列表中,在构造函数函数体中对它们赋值不起作用。
         没有默认构造函数的类类型的成员,以及 const 或引用类型的成员,必须在初始化列表中完成初始化。
    class ConstRef 
    public: 
         ConstRef(int ii); 
    private: 
         int i; 
         const int ci; 
         int &ri; 
    }; 
    ConstRef::ConstRef(int ii) 
    {
         i = ii;   // ok 
         ci = ii;  // error
         ri = i;   // 
    }
         应该这么初始化:
    ConstRef::ConstRef(int ii): i(ii), ci(i), ri(ii) { } 
    3.2 成员初始化的次序
         每个成员在构造函数初始化列表中只能指定一次。重复初始化,编译器一般会有提示。
         成员被初始化的次序就是定义成员的次序,跟初始化列表中的顺序无关。
    3.3 初始化式表达式
         初始化式可以是任意表达式
    Sales_item(const std::string &book, int cnt, double price): isbn(book), units_sold(cnt), revenue(cnt * price) { }
    3.4 类类型的数据成员的初始化式
         初始化类类型的成员时,要指定实参并传递给成员类型的一个构造函数,可以使用该类型的任意构造函数。
    Sales_item(): isbn(10, '9'), units_sold(0), revenue(0.0) {}
     3.5 类对象的数据成员的初始化      
         在类A的构造函数初始化列表中没有显式提及的每个成员,使用与初始化变量相同的规则来进行初始化。
         类类型的数据成员,运行该类型的默认构造函数来初始化。
         内置或复合类型的成员的初始值依赖于该类对象的作用域:在局部作用域中不被初始化,在全局作用域中被初始化为0。假设有一个类A,
    class A
    {
        public:
            int ia;
            B b;
    };

        A类对象A a;不管a在局部作用域还是全局作用域,b使用B类的默认构造函数来初始化,ia的初始化取决于a的作用域,a在局部作用域,ia不被初始化,a在全局作用域,ia初始化0。

    4 默认构造函数 
         不含形参的构造函数就是默认构造函数。     
         只要定义一个对象时没有提供初始化式,就使用默认构造函数。如: A a;
         为所有形参提供默认实参的构造函数也定义了默认构造函数。例如:
    class A
    {
    public: 
         A(int a=1,char c =''){}
    private:  
         int ia;
         char c1;
    };
    4.1 合成的默认构造函数
         只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数。
         一个类只要定义了一个构造函数,编译器也不会再生成默认构造函数。
    建议:
         如果定义了其他构造函数,也提供一个默认构造函数。
         如果类包含内置或复合类型(如 int& 或 string*)的成员,它应该定义自己的构造函数来初始化这些成员。每个构造函数应该为每个内置或复合类型的成员提供初始化。
     
    5 隐式类类型转换
    5.1 只含单个形参的构造函数能够实现从形参类型到该类类型的一个隐式转换
    class A
    {
    public:
         A(int a)
         {
              ia =a;
         }
     
         bool EqualTo(const A& a)
         {
              return ia == a.ia;
         }
     
    private:
         int ia;
    };
     
    A a(1);
    bool bEq = false;
    bEq = a.EqualTo(1);//参数为1,实现从int型到A的隐式转换
     
    5.2抑制由构造函数定义的隐式转换
         通过将构造函数声明为 explicit,来防止在需要隐式转换的上下文中使用构造函数: 
    class A
    {
    public:
         explicit A(int a )
         {
              ia =a;
         }
     
         bool EqualTo(const A& a)
         {
              return ia == a.ia;
         }
     
    private:
         int ia;
    };
         通常,除非有明显的理由想要定义隐式转换,否则,单形参构造函数应该为 explicit。将构造函数设置为 explicit 可以避免错误。
     
     
    三 复制控制
    1 复制构造函数
    1.1 几个要点
    (1) 复制构造函数
         复制构造函数是一种特殊构造函数,只有1个形参,该形参(常用 const &修饰)是对该类类型的引用。
    class Peopel
    {
    public:
         Peopel();//默认构造函数
         Peopel(const Peopel&);//复制构造函数
         ~Peopel();//析构函数
    };
         当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。
    Peopel a1; Peopel a2 = a1;
         当将该类型的对象传递给函数或函数返回该类型的对象时,将隐式使用复制构造函数。
    Peopel Func(Peopel b){...}
    (2)析构函数
         析构函数是构造函数的互补:当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数。
         析构函数可用于释放构造对象时或在对象的生命期中所获取的资源。
         不管类是否定义了自己的析构函数,编译器都自动执行类中非 static 数据成员的析构函数。
    (3) 复制控制
         复制构造函数、赋值操作符和析构函数总称为复制控制。编译器自动实现这些操作,但类也可以定义自己的版本。
    (4) 两种初始化形式
         C++ 支持两种初始化形式:直接初始化和复制初始化。直接初始化将初始化式放在圆括号中,复制初始化使用 = 符号。
         对于内置类型,例如int, double等,直接初始化和复制初始化没有区别。
         对于类类型:直接初始化直接调用与实参匹配的构造函数;复制初始化先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。直接初始化比复制初始化更快。

    (5)形参和返回值
         当形参或返回值为类类型时,由该类的复制构造函数进行复制。 
    (6)初始化容器元素
         复制构造函数可用于初始化顺序容器中的元素。例如:
    vector<string> svec(5);
         编译器首先使用 string 默认构造函数创建一个临时值,然后使用复制构造函数将临时值复制到 svec 的每个元素。 
    (7)构造函数与数组元素
         如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素。
         如果使用常规的花括号括住的数组初始化列表来提供显式元素初始化式,则使用复制初始化来初始化每个元素。根据指定值创建适当类型的元素,然后用复制构造函数将该值复制到相应元素:
    Sales_item primer_eds[] = { string("0-201-16487-6"),
                                     string("0-201-54848-8"),
                                     string("0-201-82470-1"),
                                     Sales_item()
                                   };


    1.2 合成的复制构造函数
    (1)合成的复制构造函数
         如果没有定义复制构造函数,编译器就会为我们合成一个。
         合成复制构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本。
    逐个成员初始化:合成复制构造函数直接复制内置类型成员的值,类类型成员使用该类的复制构造函数进行复制。
    例外:如果一个类具有数组成员,则合成复制构造函数将复制数组。复制数组时合成复制构造函数将复制数组的每一个元素。

    1.3 定义自己的复制构造函数
    (1) 只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义复制构造函数,也可以复制。 
    class Peopel
    {
    public:
         std::string name;
         unsigned int id;
         unsigned int age;
         std::string address;
    };
    (2) 有些类必须对复制对象时发生的事情加以控制。
         例如,类有一个数据成员是指针,或者有成员表示在构造函数中分配的其他资源。而另一些类在创建新对象时必须做一些特定工作。这两种情况下,都必须定义自己的复制构造函数。
         最好显式或隐式定义默认构造函数和复制构造函数。如果定义了复制构造函数,必须定义默认构造函数。
     
    1.4 禁止复制
         有些类需要完全禁止复制。例如,iostream 类就不允许复制。延伸:容器内元素不能为iostream 
         为了防止复制,类必须显式声明其复制构造函数为 private。

    2 赋值操作符
         与复制构造函数一样,如果类没有定义自己的赋值操作符,则编译器会合成一个。
    (1)重载赋值操作符
    Sales_item& operator=(const Sales_item &);
    (2)合成赋值操作符
         合成赋值操作符会逐个成员赋值:右操作数对象的每个成员赋值给左操作数对象的对应成员。除数组之外,每个成员用所属类型的常规方式进行赋值。对于数组,给每个数组元素赋值。
    (3)复制和赋值常一起使用 
         一般而言,如果类需要复制构造函数,它也会需要赋值操作符。 

    3 析构函数
         构造函数的用途之一是自动获取资源;与之相对的是,析构函数的用途之一是回收资源。除此之外,析构函数可以执行任意类设计者希望在该类对象的使用完毕之后执行的操作。
    (1) 何时调用析构函数
    • 撤销(销毁)类对象时会自动调用析构函数。
    • 变量(类对象)在超出作用域时应该自动撤销(销毁)。
    • 动态分配的对象(new A)只有在指向该对象的指针被删除时才撤销(销毁)。
    • 撤销(销毁)一个容器(不管是标准库容器还是内置数组)时,也会运行容器中的类类型元素的析构函数(容器中的元素总是从后往前撤销)。
    (2)何时编写显式析构函数
         如果类需要定义析构函数,则它也需要定义赋值操作符和复制构造函数,这个规则常称为三法则:如果类需要析构函数,则需要所有这三个复制控制成员。
    (3)合成析构函数
         合成析构函数按对象创建时的逆序撤销每个非 static 成员,因此,它按成员在类中声明次序的逆序撤销成员。
         对于每个类类型的成员,合成析构函数调用该成员的析构函数来撤销对象。
         合成析构函数并不删除指针成员所指向的对象。 所以,如果有指针成员,一定要定义自己的析构函数来删除指针。

         析构函数与复制构造函数或赋值操作符之间的一个重要区别:即使我们编写了自己的析构函数,合成析构函数仍然运行。
     
     
    四 友元
         友元机制允许一个类将对其非公有成员的访问权授予指定的函数
         友元可以出现在类定义的内部的任何地方。
         友元不是授予友元关系的那个类的成员,所以它们不受声明出现部分的访问控制影响。
         建议:将友元声明成组地放在类定义的开始或结尾
     
    1 友元类
    class Husband
    {
    public:
         friend class Wife;
    private:
         double money;//钱是老公私有的,别人不能动,但老婆除外
    };
     
    class Wife
    {
    public:
         void Consume(Husband& h)
         {
              h.money -= 10000;//老婆可以花老公的钱
         }
    };
     
    Husband h;
    Wife w;
    w.Consume(h);
     
    2 使其他类的成员函数成为友元
    class Husband; //1.声明Husband 
     
    class Wife //2.定义Wife类 
    {
    public:
         void Consume(Husband& h);
    };
     
    class Husband //3.定义Husband类
    {
    public:
         friend void Wife::Consume(Husband& h);//声明Consume函数。
    private:
         double money;//钱是老公私有的,别人不能动,但老婆除外
    };
     
    void Wife::Consume(Husband& h) //4.定义Consume函数。
    {
         h.money -= 10000;//老婆可以花老公的钱
    }
    注意类和函数的声明和定义的顺序:
    (1)声明类Husband 
    (2)定义类Wife,声明Consume函数
    (3)定义类Husband
    (4)定义Consume函数。
     
     
    五 static 类成员
     
    static 成员,有全局对象的作用,但又不破坏封装。
    1 static 成员变量
    static 数据成员是与类关联的对象,并不与该类的对象相关联。
    static 成员遵循正常的公有/私有访问规则。  


    2 使用 static 成员而不是全局对象有三个优点。
    (1)  static 成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突。
    (2)  可以实施封装。static 成员可以是私有成员,而全局对象不可以。
    (3)  通过阅读程序容易看出 static 成员是与特定类关联的,这种可见性可清晰地显示程序员的意图。 


    3 static 成员函数
         在类的内部声明函数时需要添加static关键字,但是在类外部定义函数时就不需要了。
         因为static 成员是类的组成部分但不是任何对象的组成部分,所以有以下几个特点:
    1) static 函数没有 this 指针
    2) static 成员函数不能被声明为 const (
    将成员函数声明为 const 就是承诺不会修改该函数所属的对象
    3) static 成员函数也不能被声明为虚函数

    4 static 数据成员 
         static 数据成员可以声明为任意类型,可以是常量、引用、数组、类类型,等等。
         static 数据成员必须在类定义体的外部定义(正好一次),并且应该在定义时进行初始化。
    建议:定义在类的源文件中名,即与类的非内联函数的定义同一个文件中。注意,定义时也要带上类类型+"::"
    double Account::interestRate = 0.035; 

    5 特殊的静态常量整型成员 
         静态常量整型数据成员可以直接在类的定义体中进行初始化,例如:
    static const int period = 30; 
         当然char 可以转换成整形,也是可以的,   static const char bkground = '#';
     
    6 其他
    (1)static 数据成员的类型可以是该成员所属的类类型。非 static 成员只能是自身类对象的指针或引用 
    class Screen 
    {
    public:
             // ...
    private:
             static 
    Screen src1; // ok
             Screen *src2;       // ok
             Screen src3;        // error
    }; 
    (2)非 static 数据成员不能用作默认实参,static 数据成员可用作默认实参
    class Screen 
    {
    public:
              Screen& clear(char = bkground);
    private:
             static const char bkground = '#';//static const整形变量可以在类内部初始化。
    };






    这段时间看了不少C++代码,也写了一个小项目,这篇文章来说一下我见到过的比较通用的两种多线程封装方式,实现平台为Linux
    首先说说地一种线程封装方式,也是我们平常见得最多的一种封装方式,是用面向对象中的继承,多态来实现的,下面来看具体的代码,这些代码使我随手写的,主要是为了说明思想,如果要用到项目中还需要完善。

    [cpp]  view plain  copy
    1. /************************************************************************* 
    2.     > File Name: Thread.cpp 
    3.     > Author: KevinFu 
    4.     > Mail: kevinfu1985@gmail.com 
    5.     > Created Time: 2014年05月26日 星期一 21时27分51秒 
    6.  ************************************************************************/  
    7.   
    8. #include<iostream>  
    9. #include <pthread.h>  
    10.   
    11.   
    12. using namespace std;  
    13.   
    14. class Thread  
    15. {  
    16. public:  
    17.     Thread(string name = "Unknown")  
    18.     {  
    19.     }  
    20.     virtual ~Thread()  
    21.     {  
    22.   
    23.     }  
    24.   
    25.     void Start()  
    26.     {  
    27.        pthread_create(&m_ThreadID, NULL, ThreadFunc, this);  
    28.     }  
    29.   
    30.     static void* ThreadFunc(void* pth)  
    31.     {  
    32.         Thread* p = static_cast<Thread*>(pth);  
    33.         p->Run();  
    34.     }  
    35.   
    36.     virtual void Run() = 0;  
    37.   
    38. private:  
    39.     pthread_t m_ThreadID;  
    40. };  
    41.   
    42.   
    43. class Test:public Thread  
    44. {  
    45. public:  
    46.     virtual void Run()  
    47.     {  
    48.         while(1)  
    49.         {  
    50.             cout<<"In Test::Run()"<<endl;  
    51.         }  
    52.     }  
    53. };  
    54. int main()  
    55. {  
    56.     Thread* thread1 = new Test();  
    57.     thread1->Start();  
    58.     sleep(1);  
    59. }  

    这里我们用Thread这个类来实现线程的封装,用户自己要启用的线程类都要继承这个Thread类,在Thread类的Start函数里,调用了pthread_create创建了一个线程,并将ThreadFunc设置为线程函数,把线程的this指针传递给了这个函数,在这个线程函数里调用了
    虚函数Run,这个Run函数最终会利用多态调用到用户线程类的Run函数,这就是上面代码的基本原理,比较简单,这也是面向对象用的比较多的地方,也可以说是他的强大的地方,不过用起来比较别扭,我们公司的关于线程的封装就是用的这种方法,个人感觉很麻烦,不好用,用户要想启用一个线程,必须要继承Thread这个类,而且要覆盖Run这个虚函数,很麻烦。

    下面这种线程封装方式是用基于对象的封装方式,上面的封装方式是面向对象的,这种方式我们用到了boost库中的神器boost::function, boost::bind,这个神器原理就是帮定一个函数对象,函数对象可以包含参数,我们可以利用这个神器调用任意全局函数,甚至类的成员函数,
    而不需要继承自任何类,下面来看具体代码
    [cpp]  view plain  copy
    1. /************************************************************************* 
    2.     > File Name: Thread.cpp 
    3.     > Author: KevinFu 
    4.     > Mail: kevinfu1985@gmail.com 
    5.     > Created Time: 2014年05月26日 星期一 20时41分07秒 
    6.  ************************************************************************/  
    7.   
    8. #include<iostream>  
    9. #include <pthread.h>  
    10. #include <boost/function.hpp>  
    11. #include <boost/bind.hpp>  
    12.   
    13. using namespace std;  
    14.   
    15. class Thread  
    16. {  
    17.     typedef boost::function<void(void)> ThreadFunctionCallBack;  
    18. public:  
    19.     Thread(ThreadFunctionCallBack cb, string name = "Unknow")  
    20.         :m_cb(cb)  
    21.     {  
    22.     }  
    23.     ~Thread()  
    24.     {  
    25.   
    26.     }  
    27.   
    28.     void Start(void)  
    29.     {  
    30.         pthread_create(&m_ThreadID, NULL, ThreadFunction, this);  
    31.     }  
    32.   
    33.     static void* ThreadFunction(void* obj)  
    34.     {  
    35.         Thread* thread = static_cast<Thread*>(obj);  
    36.         thread->m_cb();  
    37.     }  
    38.   
    39. private:  
    40.     ThreadFunctionCallBack m_cb;  
    41.     pthread_t m_ThreadID;  
    42. };  
    43.   
    44. class Test  
    45. {  
    46. public:  
    47.     void run(void)  
    48.     {  
    49.         cout<<"In test::run()"<<endl;  
    50.     }  
    51. };  
    52.   
    53. int main()  
    54. {  
    55.     Test t;  
    56.     Thread thread1(boost::bind(&Test::run, &t));  
    57.     thread1.Start();  
    58.     usleep(100);  
    59. }  

    我们可以看到Test类不需要继承自Thread类,我们直接可以将boost::bind帮定的函数对象传递给Thread的构造函数,这里为了简单我们把this指针传递给了ThreadFunc,我们完全可以传递任何参数给ThreadFunc, 因为我们不需要使用多态,这就是基于对象的思想,比面向对象似乎更直接,使用起来更方便,更简单。

    C++11中的tr1中已经包含了boost这两大功能,boost确实是代表着最高水平的C++库,其中有很多东西值得学习,也有很多东西即将加入到标准C++库中。







    展开全文
  • 理解什么是面向对象之前先理解一下什么是面向过程。   面向过程   过程就是一件事情的先后经过;...面向过程的编程,将一个问题划分成多个子功能组成,最后依次调用。用这种编程思想编程时,流...

    理解什么是面向对象之前先理解一下什么是面向过程。

     

    面向过程

     

    过程就是一件事情的先后经过;从什么开始到什么介绍,有一个时间上的先后顺序。

    程序过程就体现在代码执行的先后顺序。

    面向过程,就是一种解决问题的思路。用这种思想解决问题时,我们关心的是一件事情的先后经过,现经过什么,后再做什么。

    在面向过程的编程中,将一个问题划分成多个子功能组成,最后依次调用。用这种编程思想编程时,流程清晰,程序结构简单。

     

    面向对象

     

    对象,简单理解就是一个实际存在的一个个体。此对象非彼"对象"。

    生活中的对象,就比如你面前的电脑,你手中的手机,反正你能直观感触到的,都是一个对象。

    Java程序中的对象,指的是通过new关键字在 堆内存 中开辟的一块空间。

    面向对象又该怎么理解呢?面向对象也是一种解决问题的思路,用这种思路解决问题时,我们关心的是问题的参与者。比如,你要去打印文档,而你又没有设备,你找到打印文档的店家,店家会把需要打印的文档打印好给你,我们不用管是怎么样的打印过程。这种思想编程时我们不需要问题是怎样得到解决的。

    在实际面向过程的编程中,开发者一般更多的时候是在调用别人写好的类的功能,这种情况下,开发者更多的是功能的调用和指挥者。

     

    面向过程和面向对象的举例:

           吃午饭:

                  面向过程:

                         1.  买菜,洗菜

                         2.  做饭

                         3.  吃饭

                         4.  收拾

                  面向对象:

                         1.  找家饭馆

                         2.  点菜

                         3.  吃饭

                         4.  结账

     

    由此可以看出面向对象和面向过程的区别:

    1. 关注点不同
      1. 面向过程:事件中的每一步功能怎么做。
      2. 面向对象:事件中的每一步功能有没有对象已经实现了,如果有直接调用。
    2. 编程效率不同
      1. 面向过程:每一步的更能都要自己实现,效率比较慢。
      2. 面向对象:大多使用的都是封装好的方法,可以直接使用,效率比较高。
    3. 使用范围不同
      1. 面向过程:适合解决需求简单的问题。
      2. 面向对象:更适合解决复杂的需求。

     

    两者的关系:面向对象是基于面向过程的。

     

    面向过程的程序设计有三种特性:封装性、继承性、多态性。

    封装性:

           封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。例如,用户使用电脑,只需要使用手指敲键盘就可以了,无须知道电脑内部是如何工作的,即使用户可能碰巧知道电脑的工作原理,但在使用时,并不完全依赖电脑工作原理这些细节。

    继承性:

           继承性主要描述的是类与类之间的关系,通过继承,可以在无须重新编写原有类的情况下,对原有类的功能进行扩展。例如,有一个飞机的类,该类中描述了飞机的普通特性和功能,而战斗机的类中不仅应该包含飞机的特性和功能,还应该增加战斗机特有的功能,这时,可以让战斗机类继承飞机类,在战斗机类中单独添加战斗机特性的方法就可以了。

    继承不仅增强了代码复用性,提高了开发效率,而且为程序的修改补充提供了便利。

    多态性:

           多态性指的是在程序中允许出现重名现象,它指在一个类中定义的属性和方法被其他类继承后,它们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同的类中具有不同的语义。例如,当听到"Cut"这个单词时,理发师的行为是剪发,演员的行为是停止表演,不同的对象,所表现的行为是不一样的。
     

     

    类与对象

    面向对象的编程思想力图在程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类与对象。

    类是对某一类食物的抽象描述,对象则是用来表示现实中该类事物的个体。

    类与对象的关系:

    类是对象的模板,对象是类的实例。

     

    类:

    类是对象的抽象,用于描述一组对象的共同特征和行为。类中可以定义成员变量和成员方法,其中成员变量用于描述对象的特征,也被称为属性。成员方法用于描述对象的行为,可简称为方法。

    注意:只有定义在类中的变量才是成员变量,定义在成员方法中的变量是局部变量。

    //定义一个类,Person是类名
    class Person {
        // //定义String变量 name,用来保存姓名
        String name;
        // 定义int变量 age,用来保存年龄
        int age;
    
        // 定义speak()方法
        void speak() {
    	int age = 18;//定义局部int变量age并赋值18
        //下面这条语句输出打印的age值是18,不论成员变量age的值是多少
    	System.out.println("永远年轻,永远" + age + "岁");
        }
    }

    对象的创建与使用

    在Java程序中,可以使用new关键字来创建对象。具体格式如下:

    类名  对象名称  =  new  类名();

    对象创建后,可以通过对对象的引用来访问对象的所有成员。

    对象名.对象成员
    //定义一个类,Person是类名
    class Person {
        // //定义String变量 name,用来保存姓名
        String name;
        // 定义int变量 age,用来保存年龄
        int age;
    
        // 定义speak()方法
        void speak() {
    	System.out.println("我的名字是:" + name + ", 我今年:" + age + "岁。");
        }
    
    }
    
    public class Demo {
        public static void main(String[] args) {
    	Person p1 = new Person();
    
    	p1.name = "旺财";
    	p1.age = 3;
    	p1.speak();
    
    	p1.name = "小华";
    	p1.age = -5;
    	p1.speak();
    
        }
    }

    运行结果:

    运行结果

    在设计该类的时候,为了解决外界的随意访问问题,要对该类的成员变量的访问做出一些限定。这就需要类的封装。

    所谓的封装,就是指定义一个类的时候,要将类中的属性私有化,即使用private关键字修饰,私有属性只能在它所在的类中才能被访问。为了让外界能够访问到私有属性,需要提供一些使用public关键字修饰的方法,其中包括获得属性值的getXxx()方法和设置属性值的setXxx()方法。
     

    //定义一个类,Person是类名
    class Person {
        // 定义私有String变量 name,用来保存姓名
        private String name;
        // 定义私有int变量 age,用来保存年龄
        private int age;
    
        // 获取name属性值
        public String getName() {
    	return name;
        }
    
        // 设置name属性值
        public void setName(String s) {
    	name = s;
        }
    
        public int getAge() {
    	return age;
        }
    
        public void setAge(int a) {
    	if (a > 0) {
    	    age = a;
    	}
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
    	Person p1 = new Person();
    	p1.setName("旺财");
    	p1.setAge(3);
    	System.out.println("我的名字是:" + p1.getName() + "我今年:" + p1.getAge() + "岁。");
    	p1.setAge(-5);
    	System.out.println("我的名字是:" + p1.getName() + "我今年:" + p1.getAge() + "岁。");
    	// 使用下面语句将会报错
    	// p1.name;
        }
    }

    运行结果:

    运行结果

    结果分析:

    在Person类中,使用private关键字将属性name和age声明为私有,对外界提供了几个公有的方法,其中getName()方法用于获取name属性的值,setName()方法用于设置name属性的值。同理,getAge()和setAge()方法分别用于获取和设置age属性的值。在main()方法中创建Person对象,设置名字年龄后打印,再次调用setAge()方法传入-5,在setAge()方法中对参数a的值进行检查,由于当前传人的值小于0,age属性没有被赋值,所以仍然为3。

     

    展开全文
  • java:有一个学生,该属性:姓名,学号,年龄要求:利用封装的思想 来对该属性进行封装,并测试。 public class DayHomeWork { public static void main(String[] args) { //创建对象 Student s = new ...
  • Java中类对象封装、继承多态(很详细)

    千次阅读 多人点赞 2020-07-02 19:43:14
    1.对象: (1)是一种抽象的数据类型,它是对某一事务的整体描述或定义,但是并不能代表某一具体的事务。例如:人(人有姓名,年龄,... //每个类中又包含属性以及方法 String name; int age; //方法 pub
  • 类和对象之间的关系?封装继承多态?

    千次阅读 2018-03-04 09:19:00
    面向对象的编程思想对象属性和行为分别称为对象属性和方法,是构成对象的两个主要因素;编程对象属性被存储一些变量里;对象行为则通过定义方法来实现。三大基本特征:封装,继承,多态。 ...
  • 5、封装一个学生Student,(自行分辨定义为类属性还是实例属性,方法定义为实例方法) - 属性:身份(学生),姓名,年龄,性别,英语成绩,数学成绩,语文成绩, - 方法一:计算总分,方法二:计算三科平均分,方法三...
  • 第一章:对象封装1.1为什么要使用面向对象现实...面向对象设计的过程就是抽象的过程,根据业务需求,关注与业务相关的属性和行为,忽略不必要的属性和行为,由现实世界的“对象”,抽象出软件开发的“对象”。...
  • Java面向对象三大特性(封装、继承、多态)

    千次阅读 多人点赞 2021-05-19 20:59:41
    文章目录前言一、封装1.封装的概念2.private实现封装3.gettersetter方法4.封装的好处二、继承1.extends实现...我们写代码的时候经常会涉及两种角色: 的实现者和类的调用者 封装的本质就是让的调用者不必太多的.
  • JAVA 面向对象 对象 封装

    万次阅读 多人点赞 2021-05-06 15:58:57
    面向对象其实是一种编程思想,通过它可以把生活复杂的事情变得简单化,从原来的执行者变成了指挥者。 面向对象是基于面向过程而言的。 面向过程强调的是过程,比如: 打开冰箱门 2. 把大象放进去 3. 关上冰箱门 ...
  • 面向对象中--封装的理解

    千次阅读 2020-03-11 11:07:44
    封装是保证软件部件具有优良的模块性...面向对象封装就 是把描述一个对象属性和行为的代码封装在一个“模块”,也就是一个类中属性用变 量定义,行为用方法进行定义,方法可以直接访问同一个对象中属性。...
  • Java之对象(学生类封装)

    千次阅读 2018-08-09 21:35:19
    /*定义一个学生属性:姓名,年龄,性别,住址,班级, 1.方法:入学方法(参数为年龄):判断学生的年龄是否大于18岁,如果大于18岁则可以入学,并打印该学生的所有信息。 2.方法:查找方法(参数为姓名,学生...
  • 类和对象、方法和属性

    千次阅读 多人点赞 2018-07-30 17:06:08
    2、:具有相似属性和方法的对象的集合  是具有相同数据成员函数成员的一组对象的集合,它为属于该的全部对象提供了抽象的描述。 3、面向对象程序设计的特点:封装 继承 多态  封装:面向对象技术封装...
  • 一、什么面向对象和面向过程? 面向对象:主要是针对的是一个对象,将所有的功能封装成一个对象,让对 象去实现具体的细节,这就好比,我们想要吃一个蛋糕,将制作蛋糕的原材 料封装后交给蛋糕房,让蛋糕房来生产...
  • Java面向对象 - 封装、继承多态

    千次阅读 2021-01-16 10:39:55
    本关任务:构造一个,把对象属性封装起来,同时提供一些可以被外界访问属性的方法。 相关知识 为了完成本关任务,你需要掌握:1.什么是封装;2.封装的意义;3.实现Java封装的步骤。 什么是封装 封装:就是隐藏...
  • 对象和封装

    2020-03-19 09:41:03
    1):具有相同特性(数据元素)和行为(功能)的对象的抽象就是。因此,对象的抽象是的具体化就是对象,也可以说的实例是对象实际上就是一种数据类型。具有属性,它是对象的状态的抽象,用数据...
  • 学习本篇文章后会了解到:的创建,为对象添加属性对象的初始化,自定义对象的输出,类属性和类方法的创建。 1. 的定义与格式 是对一群具有相同特征或者行为的事物的一个统称。 是一个模块,是...
  • (2):具有相同特性(数据元素)和行为(功能)的对象的抽象就是。因此,对象的抽象是的具体化就是对象,也可以说的实例是对象实际上就是一种数据类型。具有属性,它是对象的状态的抽象,用数据...
  • 面向对象程序设计,设计了对象封装、继承、消息传递多态等基本概念,下面就分别来谈谈这些概念: 对象(object):好比一个人,有多种属性:姓名、性别、年龄、体重等,都有多种行为:吃饭、走路等,...
  • Java基础之对象封装

    千次阅读 2019-12-11 13:35:56
    这里的对象泛指现实一切事物,每种事物都具备自己的属性和行为。面向对象思想就是计算机程序设计过程,参照现实事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过.....
  • 其实这里体现的就是封装的思想: 将数据与行为进行分离。 试想, 如果外面的程序可以随意修改一个的成员变量,会造成不可预料的程序错误, 就象一个人的名字, 不能被外部随意修改,只能通过各种给定的方法去修改这...
  • 封装2.1 封装的意义2.2 structclass区别2.3 成员属性设置为私有3. 对象的初始化清理4. C++对象模型this指针5. 友元6. 运算符重载7. 继承8. 多态 1. 类和对象概述   C++C语言的基础上增加了面向对象编程,...
  • 前言:今天第一次上C++课程。根据老师的所讲内容进度,记录C++知识!!! 第一章 问题一:什么是面向对象程序设计?... 面向对象程序设计是一种新的程序设计范型。... 程序一般由的定义和类的使用两部分组成; ...
  • Python 封装

    万次阅读 2018-06-04 14:42:42
    封装和构造可以让我们更好的组织项目结构。 本章我们来学习封装。 Student的定义及实例化,每个实例都拥有各自的namescore。现在若需要打印一个学生的成绩,可定义函数 print_score() 该函数为外的...
  • Java类和对象 详解(一)

    万次阅读 多人点赞 2016-10-06 20:48:02
    一、面向对象简述面向对象是一种现在最为流行的程序设计方法,几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的,70年代的Smaltalk语言之进行了应用,后来根据面向对象的设计...
  • 定义一个抽象Person,包含抽象方法eat(),封装属性name、sex、age,声明包含三个参数的构造方法; 定义一个Chinese,继承自Person,重写父类的eat()方法,并定义一个自己特有的方法shadowBoxing(); 定义一个...
  • 本章主要内容 2.1 的声明和对象定义 2.2 的成员函数 2.3 对象成员的引用 2.4 封装信息隐蔽 2.5 构造函数析构函数 2.6 对象指针 2.7 动态存储 2.1的声明和对象定义 是具有相同属性和行为的一组对象...
  • 本关任务:构造一个,把对象属性封装起来,同时提供一些可以被外界访问属性的方法。 相关知识 为了完成本关任务,你需要掌握:1.什么是封装;2.封装的意义;3.实现Java封装的步骤。 什么是封装 封装:就是隐藏...
  • 面向对象day3:类和对象|封装的意义

    千次阅读 2021-09-25 09:45:33
    面向对象day3:类和对象|封装的意义 C++认为万事万物皆为对象对象上有其属性和行为. 例如: 人可以作为对象属性有年龄,性别,身高。体重…行为有走,跑,跳,吃饭… 车也可以作为对象属性有轮胎,方向盘,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 205,657
精华内容 82,262
关键字:

对象的属性和行为封装在类中吗