• 【C++】类和对象 从入门到超神


    目录

    一、 初始化列表

    1.1 自定义类型成员(无默认构造函数)

    1.2 const 成员变量

    1.3 引用成员变量

    1.4 初始化列表的注意事项

    1.5 explicit 关键字

    二、 static成员

    三、 友元

    3.1 友元函数

    3.2 友元类

    四、 内部类


    一、 初始化列表

    初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式

    现在举例一个必须使用初始化列表的场景:

    1.1 自定义类型成员(无默认构造函数)

    如果一个类中有一个自定义类型的成员,我们在构造函数中也想初始化该成员,在不使用友元和不改变访问限定符的情况下,那构造函数应该要这样写:

     那我们只能先创建一个对象,然后进行赋值,这样的方式低效,而且会有以下这种问题。

    当 Time 类不提供构造函数时(即构造函数无缺省值),这种方式就行不通了。

     所以我们只能使用初始化列表进行初始化,这就是一个必须使用初始化列表的地方。

    同样,如果自定义类型存在构造函数,也可以使用初始化列表,这里就不演示了。

    1.2 const 成员变量

    我们知道,只能在定义的时候初始化,后面则不能进行修改了,这种情况下也必须使用初始化列表,要不然无法初始化。

    1.3 引用成员变量

    除了 const ,我们知道还有引用变量在定义的时候就要初始化要,所以,这种情况也要使用初始化列表,我们来看看是怎么初始化的吧。

     上面就出现了一个问题,_y 的改变并没有影响到 x 。

     解决方法:传引用即可。

    1.4 初始化列表的注意事项

    通过以上的了解,总结如下:

    结论:

    1. 自定义类型成员,推荐使用初始化列表初始化。
    2. 初始化列表可以认为是成员变量定义的地方。
    3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表初始化,对于自定义类型成员变量,一定会先使用初始化列表初始化。
    4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。

    第二点结论我们可以推出C++11中打的那个补丁,在成员声明的地方给缺省值的作用。

    这个缺省值其实就是给的初始化列表。大家可以看下面这个变化过程,如果函数体内没有 _year=year 这条语句,其实声明时的缺省值默认给了初始化列表。

     第三点结论中,虽说推荐使用初始化列表,但是有一些场景使用函数体内初始化也是很不错的,比如在 malloc 开辟空间时:

    关于第四点结论,我们来看一道题目就懂了。 初始化按声明顺序初始化

    1.5 explicit 关键字

    我们先来看以下两种创建方式,

    其中第一个 是直接将2022传参条用构造函数,

    另外一个是根据int 类型的2022构造一个 Date 类型的临时变量,然后将该临时变量拷贝给 d2 ,只不过这个过程被编译器所优化,变成了直接调用构造函数。

    这本质是一个隐式类型的转化,就像就 int 型数据赋值给 double 型数据类似。

    而 explicit 关键字的作用就是阻止这种隐式类型的转化。那我们来看看加上explicit 关键字后的效果。


    二、 static成员

     2.1 概念

    声明为 static 的类成员称为类的静态成员,用 static 修饰的成员变量,称之为静态成员变量;

    用 static 修饰的成员函数,称之为静态成员函数。

    静态成员变量一定要在类外面进行初始化。

    静态成员变量声明和初始化举例:

     静态成员函数:

     2.2 特性

    1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
    2. 静态成员变量必须在类外定义,定义时不添加 static 关键字,类中只是声明。
    3. 类静态成员即可用 类名:: 静态成员对象.静态成员来访问。
    4. 静态成员函数没有 this 指针,不能访问任何非静态成员。
    5. 静态成员也是类的成员,受 public、protected、private 访问限定符的限制。

    特性一:所有类对象共享

    特性三:有两种访问方式,(注意:静态成员同样受访问限定符限制) 

    特性四:

     特性五:


    三、 友元

    友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

    友元分为:友元函数友元类

    3.1 友元函数

    友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数不属于任何类,但需要在想要进行友元的类中进行内部声明,声明时需要加 friend 关键字

    使用场景:

    我们想写一个打印 Date 类中成员的 流操作符重载的全局函数,如下:

    此时,这个全局函数是无法访问到类中的私有成员的,所以我们加上 friend,声明这个全局函数是 Date 类的友元。

    这样就可以直接访问类中的成员了,注意一定要是全局函数噢。

    友元函数说明:

    1. 友元函数可访问类的私有和保护成员,但不是类的成员函数
    2. 友元函数不能用 const 修饰
    3. 友元函数可以在类定义的任何地方声明不受访问限定符的限制。
    4. 友元函数的调用和普通函数调用原理相同。 
    5. 一个函数可以是多个类的友元函数。

    如果是想让一个类中的函数可以友元的访问另一个类中的成员,就要使用下面的友元类了,我们往下看。


    3.2 友元类

    友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非共有成员。

    • 友元关系是单向的,不具有交换性。

    比如上述的 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time 类的私有成员变量,但想在 Time 类中访问 Date 类中私有的成员变量则不行。

    • 友元关系不能传递

    如果 C 是 B 的友元,B 是 A 的友元,则不能说明 C 是 A 的友元。

    使用场景:

    我们上面写的 Date 类和 Time 类,我们想在 Date 类中打印出 Time 类的成员,我们就可以使用友元类。

    直接在 Date 中调用 Time类中的成员,很明显是不允许的,这时我们就可以使用友元类。 

    使用友元后:


    四、 内部类

    概念:如果一个类定义在另一个类的内部这个内部类就叫做内部类。内部类是一个独立的类,他不属于外部类,共呢个不能通过外部类的对象取访问内部类的成员。外部类对内部类没有任何优越的访问权限。

     

    注意:

    1. 内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
    2. 内部类在外部类的 public、protected、pribate 定义都是可以的,但是受访问限定符限制。
    3. 注意内部类可以直接访问外部类中的 static 成员,不需要外部类的对象/类名。
    4. sizeof(外部类)=外部类,和内部类没有任何关系。

    特性1 与 特性 3:

    因为 B 天生就是 A 的友元,所以 B 可以访问到 A 中的成员,我们以此举一个打印的例子: 

     特性4:

    sizeof (外部类) 就是外部类的大小,与内部类无关,两个类的大小是没有关联的。

  • 相关阅读:
    二分查找binary search
    【Unity入门计划】Unity实例-C#如何通过封装实现对数据成员的保护
    3.【刷爆LeetCode】找出字符串中第一个只出现一次的字符(多方法、多思路)
    数字图像处理实验目录
    融合之力:数字孪生、人工智能和数据分析的创新驱动
    神经网络示意图怎么画,ppt画神经网络模型图
    实体属性映射框架mapstruct
    想要精通算法和SQL的成长之路 - 全排列
    NextJS工程部署到阿里云linux Ecs
    Django之视图层
  • 原文地址:https://blog.csdn.net/Brant_zero/article/details/126490431