c++类与对象(终)

 文章目录

前言

  • 一、类型转换
  • 二、static
  • 三、<< && >> 运算符重载与友元函数
  • 四、内部类
  • 五、匿名对象
  • 六、对象拷贝时的编译器优化


前言

c++自定义类型类型转换、static定义、static成员变量与static成员函数、<< && >> 运算符重载与友元函数、内部类、匿名对象、对象拷贝时的编译器优化

一、类型转换

           1.类型转换分类:

           (1):强制类型转换

                        (double)1

                        强制类型转换语法: (类型)

           (2):隐式类型转换

                        double a = 1;

                        将int类型的数据赋值给double类型的变量,会产生隐式类型转换

                        const double& a = 1;

                        使用double类型的const引用去引用int类型的数据,会产生隐式类型转换

          2.类型转换的过程

           (1):(double)1

                           编译器根据double(要转换的类型)开辟空间,

                           1(被转换的数据)转换到开辟的空间,形成临时对象

           (2):double a = 1;

                         编译器根据double(要转换的类型)开辟空间

                         1(被转换的数据)转换到开辟好的空间,形成临时对象

                         再将临时对象赋值给a

           (3):const double& a = 1;

                        编译器根据double(要转换的类型)开辟空间

                        1(被转换的数据)转换到开辟好的空间,形成临时对象

                        最终a引用的是临时对象

                        注:临时对象具有常性,所以要使用const引用

                               临时对象一旦被引用,临时对象的生命周期就跟随着引用走

           3.内置类型转换自定义类型

            (1):内置类型转换自定义类型的过程

                         编译器根据自定义类型(要转换的类型)开辟空间

                         使用内置类型构造这一块空间,形成临时对象

                          再使用临时对象拷贝构造自定义类型

                          编译器优化后:直接使用内置类型的数据构造自定义类型

                          所以内置类型转换为自定义类型必须有对应的构造函数

            (2):单一内置类型转换为自定义类型

                         

              (3):多个内置类型转换为自定义类型

               

                                   

              (4):内置类型转换为自定义类型的本质:

                           使用内置类型的数据构造自定义类型对象

                           所以要使得内置类型能够转换为自定义类型

                           需要有对应的构造函数

          4.自定义类型1转换为自定义类型2

           (1):自定义类型1转换为自定义类型2的过程

                        编译器根据自定义类型2开辟空间

                        再使用自定义类型1去构造这一块空间

                        最后再将这一块空间的数据拷贝构造自定义类型2

                        编译器优化后:使用自定义类型1构造自定义类型2

                        所以要实现自定义类型1转换为自定义类型2

                        必须拥有对应的构造函数

           (2):自定义类型1转换为自定义类型2的本质

                        使用自定义类型1去构造自定义类型2

                        所以为了实现自定义类型1可以转换为自定义类型2

                        必须有对应的构造函数

        5.关于自定义类型的转换都是通过构造函数完成

        6.如果不想使得构造函数可以完成类型转换构造函数前面加explicit就不再支持类型转换

二、static

        1.作用域和生命周期

        (1):作用域

                     局部对象的作用域:局部对象所在的局部范围

                     全局对象的作用域:整个程序

       (2):生命周期

                     局部对象的生命周期:进入局部对象的作用域生命周期开始

                                                         出了局部对象的作用域生命周期结束

                     全局对象的生命周期:整个程序

         2.static作用

         (1):static修饰局部变量

                      static修饰的局部变量会在静态区创建

                      static修饰的局部变量生命周期是整个程序

                      static修饰的局部变量作用域不变

                      static修饰的局部变量只会在执行到这一条语句时创建一次

                      使用场景:如果在函数内部、类域内部需要一个像全局变量一样出来作用域不销毁

                      并且值一直保留,就使用static修饰局部变量

          (2):static修饰全局变量

                       static修饰的全局变量会由外部链接属性转换为内部链接属性

                       static修饰的全局变量只可以在本文件中使用

                       static修饰的全局变量不会进入符号表

          (3):static修饰函数

                       static修饰的函数由外部链接属性转换为内部链接属性

                       static修饰的函数只可以在本文件中使用

                       static修饰的函数不会进入符号表

         3.static成员变量

          (1):类中可以声明static成员变量,static成员变量只可以在类外定义初始化

          (2):static成员变量不是单独属于某一个对象

                       static成员变量属于整个类(可以理解为类的全局变量)

                       static成员变量属于全部的对象

          (3):static成员变量存储在静态区

                       static成员变量生命周期是整个程序

                       static成员变量受类域和成员访问限定符的限制

          (4):static成员变量属于类,不单独属于某个对象,属于全部对象

                       所以对象在开辟空间时,不会为static成员变量开辟空间

                       计算对象的大小也不会计算static成员变量

                       而且static成员变量存储在静态区,而对象在栈区

          (5):a.因为static成员变量存储在静态区,而对象存储在栈区

                          所以static成员变量不属于某一个对象

                          但是static成员变量属于类,所以对象都可以访问static成员变量

                          所以static成员变量属于全部的对象,属于整个类

                       b. 因为static成员变量存储在静态区

                           所以static成员变量必须在类外定义初始化

                           在类内只可以使用构造函数的初始化列表和函数体

                           为对象初始化,static成员变量不属于某一个对象

                           所以static成员变量不可以出现在构造函数初始化列表和函数体

                           所以static成员变量只可以在类外通过指定类域进行定义初始化

                        c.因为static成员变量存储在静态区

                           所以static成员变量不可以给缺省值/默认值

                           给成员变量缺省值/默认值是成员变量在经历初始化列表时使用的

                           而static成员变量存储在静态区,不属于某一个对象

                           所以static成员变量不会走初始化列表

                           因此static成员变量不可以给缺省值/默认值                

          (6):使用场景

                        如果类中需要一个像全局变量一样生命周期整个程序,并且数据一直存在

                        那么就是用static成员变量,static成员变量可以更好的维护类的封装

         4.static成员函数

           (1):static成员函数没有this指针,所以static成员函数不可以访问普通的成员变量

           (2):static函数可以访问static成员变量

                        因为static成员变量存储在静态区,static成员变量属于整个类

                        所以static成员函数可以访问static成员变量

           (3):访问static成员函数使用对象.static成员函数 || 类域::static成员函数都可以

                        因为static成员函数属于类,所以对象.sataic成员函数是可以的

                        因为static成员函数没有this指针,所以static成员函数不需要对象也可以调用

                        static成员函数只需要指定类域就可以调用

                        普通的成员函数必须通过对象.成员函数进行调用

                        因为普通的成员函数拥有this指针,如果不是通过对象调用

                        那么普通成员函数的this指针就没办法确定

                        所以普通成员函数必须通过对象.成员函数进行调用

                        不同成员函数不可以通过指定类域进行调用

         5.static局部变量和全局变量

         (1):static局部变量和全局变量生命周期都是整个程序

                      static局部变量和全局变量都在静态区存储

         (2):static局部变量受作用域限制

                      全局变量不受作用域限制

         (3):全局变量在main函数之前创建

                      static局部变量在运行到static局部变量时创建

                      static局部变量只会创建一次

         (4):函数栈帧销毁时,函数内部的局部变量会一起销毁

                      当main函数栈帧销毁时,main函数的局部变量会一起销毁

                      当main函数栈帧销毁完毕(main函数内部的局部变量销毁完毕时)

                      再去静态区销毁全局变量和static局部变量

                      有限销毁static局部变量再销毁全局变量

三、<< && >> 运算符重载与友元函数

       1.所需运算符重载特性:

        (1):运算符重载函数可以给运算符一个新的含义

        (2):运算符重载函数只能重载已经存在的运算符

                     运算符重载函数不可以定义新的运算符

        (3):运算符重载函数是为了使得自定义类型的对象也可以使用运算符

                     运算符重载函数参数中至少有一个是自定义类型的对象

        (4):二元运算符重载函数的参数,第一个参数 == 左操作数 第二个参数 == 右操作数

      2.cout和cin

       (1):cout是ostream类型的全局对象
                    cin  是istream类型的全局对象

       (2):<< 是在ostream类型中运算符重载函数重载过后的

                    >>是在istream类型中运算符重载函数重载过后的

                 (运算符重载函数可以给运算符一个新含义)

                   

        (3):cout << i                       ==                cout.operator<<(i)

                     之所以cout和cin自动识类型是因为函数重载

        3.自定义类型的<< && >> 运算符重载函数

        (1):自定义类型的<< && >> 运算符重载函数不推荐写成成员函数

                     因为<< && >> 运算符重载函数右两个参数

                     第一个参数是ostream/istream类型对象的引用,第二个参数是自定义类型的引用

                     如果重载成自定义类型的成员

                     第一个参数 == this指针 == 自定义类型的对象

                     不符合,c++运算符重载函数的参数位置是写死的

                    (第一个参数:左操作数            第二个参数:右操作数)

        (2):自定义类型的<< && >> 运算符重载函数推荐写成全局函数

                     因为<< && >> 运算符重载函数

                     第一个参数必须是ostream/istream类型对象的引用

                     第二个参数必须是自定义类型对象的引用

                     写成全局函数参数就可以使得第一个参数是ostream/istream类型对象的引用

                     第二个参数是自定义类型对象的引用

         (3):当将自定义类型的<< && >> 运算符重载函数写成全局函数之后,

                      在类外自定义类型的私有是不可以被访问的

                      << && >> 运算符重载函数多多少少会使用到自定义类型的私有

                      那么此时就可以将<< && >> 运算符重载函数在自定义类型中声明成友元全局函数

       4.友元

       (1):友元的作用

                    友元提供了一种突破成员访问限定符限制的方式

                    在类外的函数/类想使用类的私有就可以在类中声明友元函数和友元类

                    在类外像使用类的私有就可以使用友元

       (2):友元函数/友元类的声明

                    在类中任意位置声明 

                    friend   返回类型 函数名 (参数);

                    friend class 类名;

      (3):友元函数可以访问类的私有/保护成员

                   友元函数仅仅是一种声明,友元函数不是类的成员函数

      (4):友元可以在类中的任意地方声明,不受类的成员访问限定符的限制

      (5):一个函数可以是多个类的友元函数

      (6):类的成员函数也可以是另一个类的友元函数

                   可以访问另一个类的私有/保护

      (7):友元类的关系是单向的,不具有交换性

                   A类是B类的友元,但是B类不是A类的友元

      (8):友元关系不具有传递性

                   A类是B类的友元  B类是C类的友元 A类不是C类的友元

      (9):友元会增加耦合度,友元会破坏封装不宜多用

四、内部类

      1.内部类的概念

         在类中定义一个类,那么该类称作内部类

      2.理解内部类的方式

          使用理解域的思维理解内部类

      3.内部类和外部类是两个独立的类

         内部类只是收到外部类的类域和类的成员访问限定符的限制

         外部类的对象不会包含内部类,外部类和内部类是像个独立的类 

      4.内部类默认是外部类的友元类,内部类可以访问外部类的私有/保护

          外部类不可以访问内部类的私有/保护

      5.如果内部类放置在外部类的public位置,那么只需要突破类域使用域作用限定符就可以使用

         如果内部类放置是外部类的priveat/protected位置

         那么该内部类就是外部类的专属内部类,不可以在其他地方使用

五、匿名对象

       1.对象分类:

          有名对象、临时对象、匿名对象

       2.有名对象

           类型 对象名();

           有名对象的生命周期 == 作用域

       3.临时对象(临时对象是由编译器自动生成的,临时对象具有常性)

          类型转化、传值返回、表达式运算中都会产生临时对象

          临时对象的生命周期:当前产生临时对象的语句指向完毕后,临时对象销毁

          当临时对象被引用时,临时对象的生命周期 == 引用的生命周期

          临时对象的引用使用const引用

        4.匿名对象(匿名对象是由程序员自己生成的,匿名对象具有常性)

           类型(参数);

           匿名对象的生命周期:执行匿名对象的这一行

           开始执行匿名对象这一行代码时,匿名对象创建,执行完匿名对象这一行代码时,

           匿名对象销毁

           当匿名对象被引用时,匿名对象的生命周期 == 引用的生命周期

           匿名对象的引用使用const引用

           如果当前只需要定义一个对象用一下即可,就可以使用匿名对象

           例:只需要一个对象用来调用成员函数,就可以使用匿名对象直接调用

六、对象拷贝时的编译器优化

          1.现代编译器为了尽可能提升程序的效率,在不影响正确的情况下

             会尽可能减少一些传参和传值返回过程中的拷贝

          2.如何优化c++没有规定

             主流:

           (1):一个表达式中连续拷贝会进行合并优化

           (2):跨行跨表达式优化
         3.详情:

         (1):传值传参   构造 + 拷贝构造

         (2):隐式类型转换   构造 + 拷贝构造 ---> 直接构造

         (3):一个表达式中,连续的构造 + 拷贝构造 ---> 优化为一个构造

         (4):构造/拷贝构造 + 赋值运算符重载 == 无法优化

          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值