c++初阶——类和对象(下)

大家好,我是小锋,今天我们来学习我们类和对象的最后一个章节,我们本期的内容主要是类和对象的一些细节进行讲解

再谈构造函数

我们在初始化时有两种方式一种是函数体内初始化,一种是初始化列表

我们先来看看日期类的初始化

构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

初始化列表

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

简单来说初始化列表是每个成员定义的地方,这个时候大家要问了,这个初始化列表有什么用?

那让我们来看看

1,const 成员变量

我们正常写在函数体中是不是就行不通过了,这是因为const 成员变量在定义时就必须初始化

我们用初始化列表就可以了

2,引用的成员变量

还是使用初始化列表就可解决

3,自定义类型成员初始化 (该类没有默认构造函数)

注意: 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

接下来我们来看看初始化列表的一些细节

我们来从代码中来分析

我们对上面的代码进行调试我们可以发现在初始化列表,我们并没有写_day的定义,编译器会自动定义并且赋随机值,

其实,初始化列表是成员变量定义的地方,而我们在类中写的成员变量是在声明,不管我们写不写初始化列表,成员变量都会先在初始化列表先定义,内置类型就赋随机值,自定义类型就调用默认的构造函数,进行赋值。

当我们给了显示值,在初始化是就用显示值初始化,没有就用缺省值初始化。

初始化列表初始化的顺序是,变量声明的顺序。

总结

1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

引用成员变量

const成员变量

自定义类型成员(该类没有默认构造函数)

3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

explicit关键字

我们先来看下面的一段代码

可能有些同学会不信我们可以来验证一下(因为编译器优化,所以要想看见过程可以使用比较老的编译器),我们这里从另一个角度去分析

如果我们不想发生隐式类型转换,可以用explicit关键字去修饰构造函数

像这样

这样就禁用了隐式类型转换

在c++11中加入了多参数的隐式类型转换

static成员

引出

问大家一个问题,我们怎么知道我们构造了多少个对象,又怎么知道有多少个对象正在被使用

对于这个问题我们很自然的想到一个解决方法,定义两个全局变量来记录构造和销毁的对象

如下,

思路就是这样的,但是我们知道c++对比c语言的地方是c++面向对象所以的功能都封装起来,这样用全局变量,有问题,每个人都可以更改。那我们怎么解决这个问题呢?

这里就要用到我们的static成员了

概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化

我们来看看怎么使用

这里为什么会报错啊?这里其实跟命名空间域类似,静态成员变量属于类域编译器是不会直接访问域中的数据,但是我们可以用一些突破类域的方法去访问

大家看这样是不是就可以访问到域中的数据了?

当然这里我们是令它为公有的才可以访问,

我们注意到为什么我们这里用空指针也可以访问到m和n,这么说m和n并没有存储在类中?

我们验证一下

这么看是不是说明m和n并没有存储在类中,其实m和n是属于静态变量存储在静态区中

那如果我们不是公有的,而是私有应该这么访问m和n,

这里我们可以创建函数来访问,或者通过函数来获取m和n的值。

我们还可以用静态成员函数来访问

它的特点是没有this指针,所以无法访问对象的成员变量,我们来验证一下

大家看是不是无法访问??

我们接下来看看静态成员变量的特性

特性

1. 静态成员为所有类对象所共享,不属于某个具体的实例

2. 静态成员变量必须在类外定义,定义时不添加static关键字

3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问

4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

5. 静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

6,静态成员函数不可以调用非静态成员函数,非静态成员函数可以调用类的静态成员函数

友元

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

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

友元函数

我们来看下面这段代码

这里<<和>>为什么支持内置类型不支持自定义类型?

我们大家来看

这里支持内置类型不是直接支持而是对每个内置类型都进行了函数重载,以及运算符重载

大家看所以的内置类型都可以通过<<输出并且自动识别类型,本质是函数重载

那我们是不是也可以写一个函数来实现输出自定义类型的流插入

大家看为什么还是不行?

首先我们来分析<<这个是应该有两操作数并且位置应该对应,我们知道成员变量在调用成员函数是会隐藏地传一个this指针过去,这是this指针在右out在左是不是顺序不对啊,我们调换过来就行了

虽然可行但是,这样使用与我们平常的使用习惯不符,所以我们一个把他的位置调换,但是在类中this指针默认是在第一个,所以我们一个把函数定义在全局中。

这里我们又会遇到一个新的问题,我们定义在全局,无法访问到类的成员变量了。

这个时候我们友元函数就派上用场了。(不是只能用友元,只是一个例子)

这里的frend是一种声明,说明该函数可以访问类中的成员变量。

那接下来我们把>>也一起实现

说明:

友元函数可访问类的私有和保护成员,但不是类的成员函数

友元函数不能用const修饰

友元函数可以在类定义的任何地方声明,不受类访问限定符限制

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

友元函数的调用与普通函数的调用和原理相同

友元类

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

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

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

友元关系不能传递

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

注意,友元尽量不用

内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

注意:此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。

注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

特性:

1. 内部类可以定义在外部类的public、protected、private都是可以的。

2. 注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。

3. sizeof(外部类)=外部类,和内部类没有任何关系。

我们来一步一步验证

大家看B是A的内部类,只受A域,以及访问限定符的限制,A,B是两个独立的类

大家看在定义时受到了A域的限制

大家看这里我们可以看出B类默认时A类的友元类。

匿名对象

就是没有名字的对象,我们来看一下它的定义

从上面的代码中我们可以看到匿名对象与有名对象定义的不同

并且匿名对象的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数

那又同学可能要问了,匿名对象有什么用呢?

我们来想一个场景当我们只简单的需要调用类的一个成员函数时,我们就可以直接定义匿名对象直接调用。

我们只是简单调用,不需要定义一个有名对象。

注意:匿名对象,临时对象具有常性。

const可以延长匿名对象的声明周期

当A类型的引用出了作用域后A的匿名对象才调用析构函数。

   以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。 

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在面向对象的编程中,C语言并不直接支持类和抽象的概念。引用中提到,final关键字用来修饰方法,表示该方法不能在子类中被覆盖。而abstract关键字用来修饰抽象方法,表示该方法必须在子类中被实现。然而,在C语言中,没有对应的关键字来实现类和抽象的概念。 相反,C语言通过结构体来模拟类的概念。结构体是一种用户自定义的数据类型,可以包含多个不同类型的数据成员。通过结构体,我们可以将相关的数据和功能组合在一起。然而,C语言中的结构体不支持继承和多态等面向对象的特性。 在C语言中,我们可以使用函数指针来模拟抽象类和接口的概念。函数指针可以指向不同的函数,通过使用函数指针,我们可以实现多态性,即在运行时根据函数指针指向的具体函数来执行不同的操作。 综上所述,C语言并不直接支持面向对象中的类和抽象的概念,但可以使用结构体和函数指针来实现类似的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [面向对象——类和对象](https://blog.csdn.net/shouyeren_st/article/details/126210622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [面向对象编程原则(06)——依赖倒转原则](https://blog.csdn.net/lfdfhl/article/details/126673771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值