02笔记--类和对象

//1)内存分区模型-----不同区域存放的数据,赋予不同的生命周期,灵活编程
    /*分区--四区            代码区--存放函数体的二进制代码,由操作系统进行管理---只读、共享

        常量区--存放常量(程序运行期间不能被改变的量)(字符串常量、const修饰的全局常量)
                            全局区(静态区)--存放全局变量和静态变量---程序结束之后由操作系统释放

        堆区--由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
                                    c++中主要利用new在堆区开辟内存---利用delete释放内存
                                    注意:new返回是该类型的指针应用同类型的指针来接收
                                                如int* a = new int(10)-创建一个数据, int* arr = new int[10]-创建一个数组
                                          delete释放数组时应加[],如delete[] arr;


                            栈区--由编译器自动分配释放,存放函数的参数(形参)值,局部变量等
                                    注意:不要返回局部变量的地址--存放在栈区,栈区的数据在函数执行完后自动释放

      参考:https://www.cnblogs.com/inception6-lxc/p/8686156.html
                           
    */


    //2)引用-----起别名
    /*语法        数据类型 &别名 = 原名
    注意事项    1)引用必须要初始化  
                2)引用初始化后,不可以改变
    引用做函数参数-----可以简化指针修改实参--引用传递(取代地址传递)
    引用做函数的返回值   1)不要返回局部变量的引用
                         2)函数的调用可以作为左值
    引用的本质   在c++内部实现是一个指针常量---系统内部识别别名是引用之后,自动进行解引用的操作(*)
    常量引用     使用场景:主要用来修饰形参,防止误操作
                 注意:引用必须引一块合法的内存空间  反例: int a = 10; int &ref = 10;错误,内存空间不合法
                       const int & ref =10;合法,
    */
    //3)函数提高
    /*
    1)函数默认参数        语法:返回值类型 函数名(形参 = 默认值){}
                        不传入值,就用默认值
    注意事项            1)若某个位置有了默认参数,那么这个位置之后从左到右必须有默认参数值
                        2)若函数的声明有默认参数,函数的实现就不能有默认参数
                            -----即声明和实现只能定义一次默认参数不能重定义默认参数,不然会造成歧义
    2)函数占位参数        语法:返回值类型 函数名(数据类型){}
                        形参列表可以有占位参数,用来做占位,调用函数时必须填补该位置
                        占位参数也可以有默认参数
    3)函数重载------函数名可以相同,提高复用性
                        函数重载满足条件:
                            1)同一个作用域下
                            2)函数名称相同
                            3)函数参数类型不同 或者个数不同 或者顺序不同
                        函数的返回值不能作为函数重载条件
    注意事项                1)引用作为函数重载条件--有无const情况
                            2)函数重载遇到函数默认参数--尽量避免,容易出现歧义性
    */
    //类和对象
    /*定义 class 类名
    {
        访问权限--private---成员 类内可以直接访问,类外不可以直接访问--子类不可以直接访问父类的私有内容
                  protected---成员 类内可以直接访问,类外不可以直接访问--子类可以直接访问父类中保护的内容
                  public---成员 类内可以直接访问,类外可以直接访问
            数据成员及成员函数
    }
    */
    /*三大特性-----封装、继承和多态
    1)封装-----意义        1)将属性和行为作为一个整体,表现生活中的事物
                            ---类中的属性和行为都称为成员,
                                    ---属性   成员属性 成员变量 数据成员
                                    ---行为      成员函数 成员方法
                        2)将属性和行为加以权限控制
               与struct的区别-----默认的访问权限不同
                                    struct默认权限为共有
                                    class 默认权限为私有
               成员属性设置为私有--优点如下
                                    1)可以自己控制读写权限
                                    2)对于写权限,可以检测数据的有效性
               
    2)对象的初始化和清理-----构造函数和析构函数--必须有,若自己不提供,编译器会提供一个空实现的构造和析构
      构造函数-----创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用            
                    语法:    类名(形参列表){}
                            1)没有返回值也不写void
                            2)构造函数名与类名相同
                            3)构造函数可以有参数,因此可以发生重载
                            4)程序在调用对象时会自动调用构造,无需手动调用,且只会调用一次
                    分类:    按参数     无参构造(默认构造) 有参构造
                            按类型     普通构造              拷贝构造 类名(const 类名 &p)--将传入的人身上的所有属性拷贝到自己身上
                    调用:    1)括号法
                                    注意1):  调用默认构造函数时不需要加()---因为编译器会认为是一个函数的声明----Person p1;
                                            调用有参构造时,直接在括号内传入参数  如Person p2(10);
                                            调用拷贝构造  如Person p3(&p2);
                            2)显示法
                                    默认--Person p1;
                                    有参--Person p2 = Person(10);
                                    拷贝--Person p3 = Person(p2);
                                    注意:Person(10)--匿名对象  特点:当前行执行结束后,系统会立即回收掉匿名对象
                                    注意2): 不要利用拷贝构造函数,初始化匿名对象--编译器会认为是对象的声明--如Preson(P3)=== Person p3;
                            3)隐式转换法
                                    有参--Preson p4 = 10;----等价于Person p4 = Person(10);
                                    拷贝--Preson p5 = p4;----等价于Person p5 = Person(p4);
                    拷贝构造函数的调用时机
                            1)使用一个已经创建完毕的对象来初始化一个新对象(常用)
                                       Person p1(20);
                Person p2(p1);
                            2)值传递的方式给函数参数传值---值传递是拷贝一个临时的副本
                            3)值方式返回局部对象--返回时返回的不是原对象,而是拷贝出来的一个副本
      析构函数-----对象销毁前系统自动调用,执行一些清理工作---析构代码,将堆区开辟数据做释放操作
                    语法:    ~类名(){}
                            1)没有返回值也不写void
                            2)析构函数名与类名相同,在前面加上~
                            3)析构函数不可以有参数,因此不可以发生重载
                            4)程序在对象销毁前会自动调用析构,无需手动调用,且只会调用一次

   构造函数调用规则

      默认情况下,c++编译器至少会给一个类添加4个函数

              --1)默认构造函数(无参,空实现);

              --2)默认析构函数(无参,空实现);

              --3)默认拷贝构造函数,对属性值进行值拷贝;

              --4)赋值运算符 operator =  对属性进行值拷贝----若类中有属性指向堆区,做赋值时也会出现深浅拷贝的问题(赋值运算符重载实现)

      构造函数调用规则:

        1)若用户定义有参构造函数,c++不在提供默认无参构造,但会提供默认拷贝构造

        2)若用户定义拷贝构造函数,c++不在提供其他构造函数

   深拷贝、浅拷贝(面试)

      浅拷贝:简单的赋值拷贝--利用编译器提供的拷贝构造函数,会做浅拷贝操作--问题(堆区的内存重复释放--自己实现拷贝构造函数,可以利用深拷贝进行解决)

      深拷贝:在堆区重新申请空间,进行拷贝操作(重新在堆区创建一块内存)

      总结:若内存有在堆区开辟的,需要自己实现拷贝构造函数释放堆区内存

      初始化列表-----用来初始化属性

      语法: 构造函数(): 属性1(值1),属性2(值2)...{}

      类对象对位类成员--成员(对象成员)

      构造顺序--当其他类的对象作为本类的成员,构造时先构造类对象,再构造自身(相当于胳膊腿)

      析构顺序--与构造相反

   静态成员--静态成员变量/函数--前面加static

      静态成员函数--1)所有对象共享一个函数---可以通过类名访问--通过对象访问

             -2)静态成员函数只能访问静态成员变量

             -3)有访问权限

3)C++对此昂模型和this指针

    1)成员变量和成员函数分开存储

        --空对象占用内存空间为:1(原因:C++编译器会给每个空对象也分配一个字节空间,为了区分空对象占内存的位置--每个空对象内存地址独一无二)

        --只有非静态成员变量属于类的对象上

        --非静态成员函数和静态成员不属于类的对象上--只有一份函数实例

    2)this指针--this指针指向被调用的成员函数所属的对象---本质是指针常量

        --隐含在每一个非静态成员函数内的一种指针,不需要定义,直接使用

        用途

          --解决名称冲突---当形参和成员变量同名时,可用this指针来区分--类似于python中self?

          --在类的非静态成员函数中返回对象本身(&引用的方式返回),可使用return *this--链式编程思想

    3)空指针访问成员函数

        空指针访问非静态成员属性时,指针为空访问不了非静态成员属性程序崩溃--防止乱传入指针加入this == NULL 判断,增强代码健壮性

    4)const修饰成员

        常函数--在成员函数()后面加const,修饰的this指针,使指针指向的值也不可修改

          --void func()  const {}

          --常函数不可以修改成员属性

          --成员属性声明时加mutable后,在常函数中可修改

        常对象--在对象前面加const

          --const Person p1

          --常对象只能调用常函数,不可以调用普通成员函数

          --成员属性声明时加mutable后,在常对象可修改

    */

原文地址:https://www.cnblogs.com/MissZhang-154/p/13210715.html