类-自定义数据类型
萧禾财 Lv4

面向对象语言编程基于于对象类型相关的三个基本概念:封装性,多态性,继承性。

面向对象的程序设计过程首先要确定解决问题需要哪些新的专用的数据类型,并把它定义为类,然后根据该问题的相关具体对象可以执行的操作编写程序。

理解类

定义类

image-20221029213817908

public关键字决定后面那些成员的访问属性。将数据成员指定为public,意味着再包含这些成员的类对象的作用域内任意位置都可以访问它。

还可将成员指定为 private 或 protected ,完全省略说明,默认访问属性是private。(结构体的类型为public)

声明类的对象

声明类的对象和声明结构体的方法完全相同。

image-20221029214610683

对象名box1表示整个对象,包括3个数据成员。对象的数据成员均没有初始化。

访问类的数据成员

可以利用直接成员选择操作符来引用类对象的数据成员。

image-20221029215003339

因为box2的数据成员的访问属性为public,所以在类外部的函数中只能以这种方式访问该数据成员。

类的成员函数

类的成员函数是其定义或原型在类定义内部的函数,它们可以处理本类的任何对象,有权访问本类的所有成员。

image-20221029215842427

注意,给类添加成员函数不会影响类对象的大小。

成员函数定义的位置

成员函数不一定要定义在类的内部。如果希望将其放在类外部定义,则需要将函数原型放在类的内部。

image-20221029221244691

因为实在类外部定义,所以要告诉编译器:该函数属于CBox类——即给函数名加上类名作为前缀,并用作用域解析运算符::(两个冒号)将二者分隔。

这样写产生的于上面的输出是一致的,但两者不是同一个程序了。在类内部定义函数时,编译器会暗中将其当作内联函数对待。

内联函数

在内联函数中,编译器会设法以函数体代码代替函数调用,这样可以避免调用函数时大量的系统开销,加快运行。

在函数定义位于类定义外部时,也可以告诉编译器将函数视为内联函数——即在函数头前面加上关键字 inline

image-20221029221836561

此时程序将于在类定义内的函数一样了。内联函数最适合用于短小精悍的简单程序。

类构造函数

构造函数的概念

类的构造函数是类的特殊的函数,在创建新的类对象时调用它,因此,该函数提供了创建对象时进行初始化的机会。

类可以有多个构造函数,以确保用不同的方式创建对象。

命名类构造函数时,函数名总是于所属类的名称相同,构造函数没有任何的返回类型。例如:CBox的构造函数时CBox()。

image-20221030132641422

上面所示的构造函数CBox()有3个double类型的形参,分别可以对m_length,m_width,m_height赋初值。

image-20221030133305989

默认的构造函数

默认的构造函数时不要求提供实参的函数,可以是没有指定任何形参的的构造函数,也可以是实参全部有默认值得构造函数。

当我们没有定义构造函数时,编译器将提供默认的无实参构造函数。当我们定义的构造函数时,编译器将不再提供默认的构造函数。

image-20221030135230211

如果我们仍然希望声明没有初始化的CBox对象时,则必须自己添加默认构造函数。

例如:

image-20221030135809474

默认的形参值

我们可以在函数原型中给函数的形参指定默认值,同样也可以对类的成员函数(包括构造函数)这样做。

例如:image-20221030140310704

此时当我声明函数时就可以不带参数,但是此时就会和默认的构造函数冲突。

image-20221030140746617

编译器不知道应该调用那个构造函数。最好的办法就是去除默认的构造函数,此时任何未显式初始化的CBox对象的数据成员将自动初始化为1.

在构造函数中使用初始化列表

我们使用显式赋值语句在类构造函数中初始化对象成员时,还可以用另一种技术——初始化列表。

image-20221030141833840

这样的初始化方式要比用赋值语句效率高。并且这是给对象的某些类型的数据成员赋值的唯一方法。

构造函数的初始话列表于形参列表之间要用冒号隔开,各个初始化的成员之间以逗号隔开。

声明显示的构造函数

现在的编译器很智能帮助简化了很多事,当我们定义了一个具有单一形量的构造函数,在使用此函数时有时就会出现隐式转化,而有时我们不希望出现隐式转化。

例如:image-20221030143848654

创建这样一个构造函数,只有一个形参。再考虑下面这段代码:

image-20221030144252062

这段代码中,调用构造函数CBox(double)创建类box,并将其赋值,此时值99要从类型double到CBox的隐式转换。有时我们并不想出现这种隐式转换情况。

此时我们就可有在构造函数的定义中使用explicit(显式的)关键字来阻止这种情况。

image-20221030192029799

构造函数声明为explicit,则只能显示的调用它,且不用于隐式转换。

此时要想把对象的成员赋值,只能这样写:

image-20221030192449337

这不是转换,而是显示的调用了含单一形参的构造函数。

还一种不希望出现隐式转换的。一个构造函数,有多个形参且都有默认值。前面出现过的:

image-20221030193007192

因为第二第三个形参有默认值,所以下面代码可以执行:

image-20221030193533999

这一次是隐式调用构造函数,第一参数会被赋值为99.0,其他两个实参值是默认值。这也不是我们所期望的。为了防止这种情况,我们要显式声明构造函数。

类的私有成员

在定义类成员时使用关键字private,此时的类成员只有类的成员函数可以访问。

image-20221030194055439

现在,3个数据成员只能被本类的尘缘函数访问。

此时在main函数中在想直接对类的数据成员赋值或使用,编译器将报错。

要注意,现在使用构造函数时唯一一种给数据成员赋值的方法。

同样的,成员函数也可以被private修饰,这种情况下,它只能被其他函数成员调用。

访问私有类成员

我们使用private关键字确实很好的保护了类成员,但是也不利于我们使用类成员。

因此我们要编写一个返回数据成员值得成员函数即可。

image-20221030195518527

当我们需要数据成员时

image-20221030201700628

这样既可以访问这些成员的值,又不会危害类的安全性。

类的友元函数

有时候由于某种原因,我们希望某些虽然不是类成员得函数能够能够访问类的所有成员——拥有特殊的权限。

这样的函数被称为类的友元函数,使用关键字friend来定义。可以在类定义中添加友元函数的原型,也可以添加整个函数的定义。在类定义内的友元函数也是内联函数。

注意,友元函数并不是类的成员,因此访问特性不适合它。这些函数知识拥有特殊权利的普通全局函数。

image-20221030211011986

  • 本文标题:类-自定义数据类型
  • 本文作者:萧禾财
  • 创建时间:2022-10-29 21:20:05
  • 本文链接:https://ipartmentxhc.github.io/2022/10/29/类-自定义数据类型/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!