cpp交通:八:创建新的类型
发布日期:2021-06-29 18:53:16 浏览次数:2 分类:技术文章

本文共 3788 字,大约阅读时间需要 12 分钟。

文章目录

8.5 const与对象

8.5.1常量数据成员

  • 类数据成员可定义为常量
  • 常量数据成员
    • 某个对象生存期内该数据成员是常量
    • 对象生成时给出常量数据成员的值
    • 在此对象生存期内,值不能变
  • 常量数据成员的声明是在该数据成员声明前加const
  • size就是常量数据成员
  • 一旦对象生成,常量数据成员值不能变
    • 值只能在构造函数中设定
    • 其他成员函数不能改
  • 构造函数如何给常量数据成员赋值?
    • 常量只能初始化,即调用构造函数,不能赋值
  • 常量数据成员初值不能在
    • 构造函数的函数中
    • 通过赋值语句设定
  • 构造函数提供初始化列表
    • 位于函数头和函数体间
  • 冒号开头
    • 逗号分隔的数据成员列表
    • 每个数据成员的后面跟着一个放在圆括号中的对应于该数据成员的构造函数的实际参数
      • 表示对该数据成员调用它的构造函数为它赋初值

构造函数的其他部分的任务就在这两个{}里面完成哈哈哈!

8.5.2常量对象

  • 常量就是在定义时给出初值
  • 整个程序运行过程中常量值不能变
  • 自定义类型和内置类型一样
    • 都可定义常量对象
  • 定义一个实型常量PI,值3.1415926,
  • 一旦将PI定义为常量,程序中不能再对PI赋值

  • 也能够定义一个常量对象
  • r1是常量对象
    • 只能初始化,不能赋值
    • 必须要初始化
  • 程序中有试图改变r1的语句时
    • 报错

  • 如果程序中有赋值r1=r2,编译器知道r1值将被改变
    • 如果rl定义为常量,就报错
  • “对象名.成员名=表达式”这样的语句时
    • 编译器也知道该对象被改
  • 如果对象是通过成员函数来操作
    • 那编译器如何知道哪些成员函数会改变数据成员
  • 它又如何知道哪些成员函数的访问对常量对象是“安全”的呢?
    • 答案是用常量成员函数

8.5.3常量成员函数

  • C++中可把一个成员函数定义为常量成员函数
    • 它告诉编译器该成员函数是安全的
    • 不改变对象的数据成员值
    • 可被常量对象调
  • 一个没有被明确声明为常量成员函数的成员函数被认为是危险,
    • 它可能修改对象的数据成员值
  • 当把某个对象定义为常量对象后,该对象只能调用常量成员函数

  • 常量成员函数的定义是在函数头后面加const

  • 要说明一个函数是常量的

    • 须在类定义中的成员函数声明时声明它为常量
    • 成员函数定义时也要说明它是常量
  • 仅在类定义中说明

    • 函数定义时没说明
    • 编译器把这两个函数看成是两个不同函数
    • 是重载函数
  • 任何不修改数据成员的函数都应声明为const类型

  • 编写常量成员函数时,不慎修改数据成员,或调用其他非常量成员函数,编译器将出错

  • 更好Rational类定义应写成

  • display函数是不会修改数据成员值,于是被定义成常量成员函数。
  • 一旦将一个Rational类的对象定义为常量的,
    • 就不能对该对象调create,add和multi函数。
    • 前一个函数将重新设置数据成员的值,
    • 后两个函数会把运算的结果存入该对象。
    • 该对象允许调用的成员函数只有 display函数。
  • 它还可以作为add和 multi的实际参数

8.6静态成员

8.6.1静态数据成员

  • 类的对象有时可能需共享一些信息
  • 银行系统中,最主要的对象是账户
    • 需定义一个账户类
    • 每个账户包含的信息有账号、存入日期、存款金额
  • 为计算利息,还需知道利率
  • 利率是每个账户对象都必须知道的信息,
    • 且对所有账户类的对象,
    • 这个值相同
  • 不必为每个对象设置这样的一个数据成员,
    • 只需让所有对象共享这样一个值就可
  • 如果用全局变量来表示这个共享数据,
    • 则缺乏对数据保护
  • 全局变量不受类的访问控制的限定,除了类的对象可以访问它以外,
    • 其他类的对象以及全局函数往往也能存取这些全局变量
    • 也容易与其他的名字相冲突。
  • 可把一个数据当作全局变量去存储
    • 但又被隐藏在类中
    • 且清楚地表示与这个类的联系

  • 用类的静态数据成员实现
  • 静态数据成员逻辑上是对象的一部分,
    • 但事实上每个对象的空间中不包含这个静态成员
  • 类的静态数据成员拥有一块单独的存储区
  • 不管创建多少个该类的对象
  • 这些对象的静态数据成员都共享这一块空间
  • 这就为这些对象提供了一种互相通信的机制,
    • 某个对象修改了它的静态成员
    • 其他对象的这个成员值也变

  • 静态数据成员是属于类的,它的名字只在类的范围内有效,且可以是公有的或私有的
  • 这又使它免受其他全局函数的干扰

说明数据成员是静态的,只需要在此数据成员前加一个保留字 static

  • 类定义只是给出了对象构成的说明,
    • 真正的存储空间在
    • 对象定义时分配
  • 静态数据成员属于类而不属于对象,
    • 系统为对象分配空间时并不包括静态数据成员的空间
  • 静态数据成员的空间必须单独分配,且必须只分配一次

  • 为静态数据成员分配空间称为静态数据成员的定义。
  • 静态数据成员定义一般出现在类的实现文件
  • Saving_Account类实现文件中,
    • 须有如下定义
  • 该定义为rate分配空间,并给它赋初值0.05
  • 没有这定义,链接器会报错

  • 静态数据成员属于类
    • 可通过作用域运算符用类名直接调
    • “类名:静态数据成员名”
  • 但从每个对象角度看
    • 又是对象一部分
    • 又可和普通的成员一样用对象引用它
  • 公有的,可用“对象名.成员名”或“对象指针->成员名”访问
  • 不管用哪一个对象去访问它,访问的都是同一块空间

8.6.2静态成员函数

  • 成员函数也可是静态。
    • 专用于且仅能操作静态数据成员的函数
  • 静态成员函数所做的操作将影响类的所有对象,
    • 而不是某一特定对象

  • 静态成员函数的声明只需要在类定义中的函数原型前加static。

  • 静态成员函数的定义可以写在类定义中,也可以写在类定义外面。

  • 类外定义时,函数定义中不用加static

  • 可用对象来调用
  • 更典型的方法是通过类名来调用,
    • 即“类名::静态成员函数名()

  • 静态数据成员逻辑上是对象的一部分,
    • 所有成员函数都可操作静态数据成员
  • 为什么还需要静态成员函数?
    • 专用于操作静态数据成员而不能操作非静态数据成员,
    • 最大特点是没有隐含的this指针
    • 保证静态成员函数不能访问一般数据成员,只能访问静态数据成员或其他静态成员函数

  • 静态成员函数只能访问静态数据成员,
    • 任何对象建立之前处理静态数据成员,
    • 如初始化静态数据成员的值
    • 普通成员函数不能实现
  • Savingaccount类静态数据成员rate,
    • 当利率发生变化时,
    • 必须修改
    • 可以设置一个静态成员函数

在这里插入图片描述

8.7友元

  • 类的封装使得私有成员只能由类的成员函数访问
  • 这有时会降低对私有成员的访问效率,函数调用会用系统的时间和空间。
  • C++中,可以对某些经常需要访问类的私有成员的函数开一扇“后门”,那就是友元。
  • 友元可以在不放弃私有成员安全性的前提下,使得全局函数或其他类的成员函数能够访问类中的私有成员。

  • 类定义中,可指定允许某些全局函数、某个其他类的所有成员函数或某个其他类的某一成员函数
    • 直接访问该类的私有成员
    • 友元函数、友元类和友元成员函数

  • 要将某函数或某类声明为自己的友元,
    • 允许它访问自己的私有成员
    • 只需要在类定义中声明此函数或类
    • 并在函数原型或类名前加friend
  • 友元函数的声明可公有部分,也可私有
  • 类A声明全局函数f是友元,f函数的原型是void f();
  • 则可在类A的定义中加入如下一条声明
friend void f();

  • 将类B的成员函数
    int func (double)i
  • 声明为A的友元,
  • 类A的定义中加入
friend int B::func(double);
  • 将整个类B作为类A的友元,
  • A定义中加入friend class B;

  • 将所有友元关系的声明集中在一起,
  • 放在类定义中的最前面或最后面,
  • 不要在它的前面添加任何访问控制说明

在这里插入图片描述

  • 声明了函数disp是Girl类的友元,

  • disp函数中可以用x.name、x.age的形式引用Girl类的对象x的私有成员。

  • 友元关系既不是对称,也不是传递

  • 友元为全局函数或其他类的成员函数访问类的私有成员函数提供了方便,

    • 破坏类的封装,
    • 给程序的维护带来了一定困难,
    • 慎用

  • 例8.11
  • 基于单链表的统计某次考试成绩的均值和方差的类

  • 例8.7
  • 一个可以实现成绩统计的类statistic.
  • 用动态数组保存学生的成绩,构造statistic类的对象时必须给出参加统计的学生人数,
  • 输入学生成绩前先要数一数这次有多少人参加考试

  • 用单链表存储学生的成绩。
  • 定义数组时需要确定整个数组的存储空间,
  • 链表不需要事先为所有元素准备好一块空间,
    • 也不需要知道一共有多少个元素,
    • 需要增加一个元素时,动态为它申请存储空间,真正做到按需分配

在这里插入图片描述

  • 每个结点由两部分
    • 真正存储数据元素
    • 存储下一结点地址
  • head存放存储第一个元素的结点的地址
    • head可以找到第一个结点
    • 第一个结点中存放着第二个结点的地址
    • 因此从第一个结点可以找到第二个结点
  • 最后一个结点的第二部分存放一个空指针,表示其后没有元素

  • 存储一个单链表需要一个指向结点的指针,保存第一个结点的地址,C++本身没有这种结点类型
  • 程序要用单链表就必须自己设计一个结点类型。
  • 每个结点由两部分数据组成:数据元素本身和指向下一结点的指针
  • 结点本身并不要特殊操作,不需要成员函数。
  • 但一般类都有构造函数,
    • 也为结点类定义一个用于对结点赋初值的构造函数

  • 结点类
    • 被统计成绩的类所用
  • 统计成绩时要用到每个结点中的数据
    • 将统计成绩的类声明为结点类的友元类

在这里插入图片描述

转载地址:https://cyj666.blog.csdn.net/article/details/108318954 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:cpp交通十:组合与继承
下一篇:C++ 多态的定义及实现

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月08日 04时45分30秒