一、什么是类,一些关键字

一、类概念:

  1.1、类是虚的。类不占内存,对象才是实际存在的。对象占用内存。

  1.2、空间分配:

    1.2.1、一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。
        自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。
        全局数据区的数据并不会因为函数的退出而释放空间。

    1.2.2、在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。
        但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。

  1.3、构造函数(构造函数的作用:初始化对象的数据成员。)和析构函数:

    1.3.1、 每次有对象产生的时候,构造函数被调用。 当对象销毁时,析构函数被调用。

    1.3.2、 构造函数和析构函数必须为public。

    1.3.3、 构造函数是可以重载的。

    1.3.4、 ClassDemo(const ClassDemo other): 产生一个临时对象然后再调用:ClassDemo operator = (const ClassDemo& other)
        进行临时对象的赋值。
        ClassDemo(const ClassDemo& other): 不会产生临时对象,效率更高。加const之后,风险也被消除了。

    1.3.5、 只有一个参数的构造函数会提升为转换构造函数,用于隐式转换。
        ClassDemo demo = 10; //(ClassDemo类中存在一个带一个参数((可以有多个有默认值的参数)的构造函数)
        所以此时相当于:ClassDemo demo(10) ;

        注意:使用explicit 修饰来禁止使用转换构造。

        需要注意的一点是,这个其实就是一般的构造函数,但是对于出现这种单参数的构造函数,

        C++会默认将参数对应的类型转换为该类类型,有时候这种隐私的转换是我们所不想要的,所以需要使用explicit来限制这种转换。

    1.3.6、默认构造函数是一个没有参数的构造函数,它仅仅负责创建对象而不做任何赋值操作。

    1.3.7、只要类中提供了任意一个构造函数,那么C++就不在自动提供默认构造函数。

    1.3.8、C++规定如果一个类对象是另外一类的数据成员,那么在创建对象的时候系统将自动调用那个类的构造函数。

    1.3.9、一个类的成员如果是另外一个类的对象的话,不能在类中使用带参数的构造函数进行初始化 。

        因为:类是一个抽象的概念,并不是一个实体,并不能包含属性值(这里来说也就是构造函数的参数了),
        只有对象才占有一定的内存空间,含有明确的属性值

    1.3.10、C++规定,所有的全局对象和全局变量一样都在主函数main()之前被构造,函数体内的静态对象则只构造一次,也就是说只在首次进入这个函数的时候进行构 造!

    1.3.11、类成员的构造是按照在类中定义的顺序进行的,而不是按照构造函数说明后的冒号顺序进行构造的,这一点需要记住!

    1.3.12、类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作。

    1.3.13、构造函数并不像普通函数那样进行一段处理,而是创建了一个对象,并且对该对象赋初值,所以显式调用构造函数无法实现给私有成员赋值的目的。

        千万不要出现使用一个构造函数显式调用另外一个构造函数,这样会出现不确定性。
        其实一些初始化的代码可以写在一个单独的init函数中,然后每一个构造函数都调用一下该初始化函数就行了。

    1.3.14、析构函数的定义:析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载,只有在类对象的生命期结束的时候,由系统自动调用。

  1.4、new和malloc:

    1.4.1、malloc 不会调用构造函数, 而new会 调用构造函数。

    1.4.2、malloc 是函数, new 是运算符。

  1.5、inline:

    1.5.1、内联函数:所谓内联函数就是在函数调用的时候函数本身是不申请栈空间的,大大提升了运行的效率,
        但是生成的体积会膨胀(代码膨胀),不会新建栈。

    1.5.2、inline函数在调用的时候,是将代码展开。

    1.5.3、inline关键字修饰的函数并不是100%会成为内联函数,会根据编译器的判断来完成。
        所以并不是所有inline函数都会被编译器认为是内联函数。

    1.5.4、内联函数与宏的区别:
        内联函数与宏的不同在于,内联函数会进行类型检查,而宏不会进行类型检查。

    1.5.5、.h 函数(声明和定义在一起),默认是inline。

  1.6、this指针:

    1.6.1、 this指针是每一个类的隐藏属性, 每一个类中都会有一个this指针。

    1.6.2、 this是用来区分不同的对象。代表对象本身。

    1.6.3、 this指针和类没有关系, 是对象的代名词。

    1.6.4、一个对象的this指针并不是对象本身的一部分。

    1.6.5、this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。

    1.6.6、this指针存在于类的成员函数中,指向被调用函数所在的类实例的地址。

    1.6.7、关于this指针的一个经典回答:

        当你进入一个房子后,   
        你可以看见桌子、椅子、地板等,   
        但是房子你是看不到全貌了。   
        对于一个类的实例来说,   
        你可以看到它的成员函数、成员变量,   
        但是实例本身呢?   
        this是一个指针,它时时刻刻指向你这个实例本身。

  1.7、const:

    1.7.1、 const方法能被非const对象调用, 而const对象只能调用const方法。

    1.7.2、 需要改变值的方法是不能为const方法的,而不改变值的方法一般使用const。
        const代表 --> 值不能被修改。

    1.7.3、 const 只能在类中才能进行修饰, 且能构成重载。const函数只有在类中有用。

    1.7.4、const与宏的区别:

      const: 1、具有类型的常量。        宏:1、不具有类型,只是单纯的替换。
          2、编译时分配空间。方便调试。    2、而宏不方便调试
          3、具有作用域              3、全局。

      1、所以const 比用宏好些, 最重要的原因是 const易于调试。

      2、const是伪常量。 const主要是给程序员看的。

  1.8、static:

    1.8.1、面向对象的static关键字(类中的static关键字)

      (1)static修饰的成员是不属于类对象的。 属于类的。
        意思就是说可以使用类来直接操作这个成员。

      (2)static修饰的成员,必须在类外部进行初始化。

      (3)只有static int(静态整型) 可以在定义的时候直接初始化, 其他的类型只能到类外进来初始化。

      (4)static成员是没有this指针的,没有对象属性

      (5)与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。
          从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。

      (6)static成员变量:被对象共享的,但是他是不属于对象的。
          可以通过类名直接访问。

      (7)static成员函数:没有this指针(无妨访问非static成员)

      (8)使用static关键字一般是为了替换全局的变量。

      (9)该变量在全局数据区分配内存;
          未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);
          静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;

      (10) 定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:

          1、静态全局变量不能被其它文件所用;

          2、其它文件中可以定义相同名字的变量,不会发生冲突;

      (11)静态数据成员有以下特点:

          对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,
          静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。
          对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;

          静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。
          在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;

          静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
          因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,
          它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;

          静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
            <数据类型><类名>::<静态数据成员名>=<值>

          类的静态数据成员有两种访问形式:
            <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

          如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;

          静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。
          所以,应该把利息设为存款类的静态数据成员。这有两个好处,

            第一,不管定义多少个存款类对象,
                利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。
            第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;

        同全局变量相比,使用静态数据成员有两个优势:

        (1)静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
        (2)可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

      (12)关于静态成员函数,可以总结为以下几点:

        出现在类体外的函数定义不能指定关键字static;

        静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

        非静态成员函数可以任意地访问静态成员函数和静态数据成员;

        静态成员函数不能访问非静态成员函数和非静态数据成员;

        由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;

        调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
          <类名>::<静态成员函数名>(<参数表>)
        调用类的静态成员函数。

    1.8.2、静态局部变量有以下特点:

      (1)该变量在全局数据区分配内存;

      (2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;

      (3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;

      (4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

    1.8.3、静态函数:

      (1)在函数的返回类型前加上static关键字, 函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

      (2)定义静态函数的好处:

        静态函数不能被其它文件所用;

        其它文件中可以定义相同名字的函数,不会发生冲突;

  1.9、命名空间:

    1.9.1、 是用来区分组织的。 解决重名的问题。要避免命名空间污染(不要用using namespace)。

  1.10、类中的默认函数:

    1.10.1、 默认存在的函数有:
      默认构造函数、默认析构函数、默认拷贝构造函数、默认赋值函数、
      取址运算符、取址运算符const。

    1.10.2、 默认的赋值函数,不管写不写重载, 它都是存在的。

        默认的赋值函数接收的参数是当前类的对象引用。

  1.11、深拷贝,浅拷贝:(深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,
  反之,没有重新分配资源,就是浅拷贝。)

    1.11.1、浅拷贝,存在风险,指针赋值,被delete, 没有维护参数的生命周期,给别人来维护了。

        深拷贝,在对象中维护了所有参数的生命周期,所有参数的生命周期都是和对象同步。

    1.11.2、 浅拷贝(两者公用了内存),深拷贝(连同内存一起,都进行了拷贝)。

    1.11.3、拷贝构造函数:

      就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。

    1.11.4、当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。
        也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。 以下情况都会调用拷贝构造函数:

      (1)一个对象以值传递的方式传入函数体

      (2)一个对象以值传递的方式从函数返回

      (3)一个对象需要通过另外一个对象进行初始化。

    1.11.5、在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,
        如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。
        这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

  1.12、类型转化:

    1.12.1、static_cast<>: 这个不是强制转换, 是表示转换 --> C++风格。

    1.12.2、const_cast<>: 特定情况下使用, const -> 非const 移除对象的常量性,
        还是不能修改内容, 是为了参数的匹配, 不实现const版本。

    1.12.3、reinterpret_cast<>: 强制转换, 二进制层面的转换。(不用), 可以用于做指针的转换。(这个转换很危险,一般不用)。

    1.12.4、dynamic_cast<>。

  1.13、引用(&), 取地址符(&), 指针(*):

    1.13.1、int number = 100;
        int &reg = number;

      1、引用就是一个别名,以后对该别名的修改都是对本名的修改。

      2、通过传入引用可以直接修改本身的值,而且避免了副本的复制。

      3、返回引用可以修改所返回的值。

      4、如果函数外部需要修改返回的值的时候, 返回引用。

      5、引用一旦确定就无法更改。

转载于:https://www.cnblogs.com/xiaohaige/p/6801451.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值