跳至正文
wyaaaattwhoAI RESEARCH & ENGINEERING
← 返回首页

Members

常成员函数及静态成员

获取vs改变对象的状态

  • 在程序运行的不同时刻,一个对象可能会处于不同的状态:
    • 对象的状态由对象的数据成员的值来体现。
  • 可以把类中的成员函数分成两类:
    • 获取对象状态(不改变数据成员的值)
    • 改变对象状态(改变数据成员的值) 例如

常成员函数

  • 为了防止在一个获取对象状态的成员函数中无意中修改对象数据成员的值,可以把它说明成常成员函数。例如
    • 编译器一旦发现在常成员函数中修改数据成员的值,将会报错!
    • 注意:对于有些修改对象状态的常成员函数,编译程序不会指出错误!
      • 常成员函数还有一个作用:对常量对象只能调用类中的常成员函数。

        静态数据成员

        • 更好地实现同类数据的共享,比全局变量更加安全
        • 采用静态数据成员可以更好地实现同一个类的不同对象之间的数据共享。例如
          • 类的静态数据成员对该类的所有对象只有一个拷贝。例如,对于下面A类中的shared:
            • notion image

          静态成员函数

          • 成员函数也可以定义成静态的(静态成员函数)。例如:
          • 静态成员函数只能访问类的静态成员。
          • 静态成员函数没有隐藏的this参数!
          • 静态成员除了通过对象来访问外,也可以直接通过类来访问。例如: A a; cout << a.get_shared(); 或者 cout << A::get_shared();
          • 我们给如下的一个例子

            友元

            友元

            • 根据数据封装的要求:
              • 类中定义的数据成员不能在外界直接访问,必须要通过类中定义的public成员函数来访问。
              • 在有些情况下,这种对数据访问的方式效率不高!
            • 某些情况下,为了提高在类的外部对类数据成员的访问效率,在C++中,
              • 可以指定某些与一个类密切相关的、又不适合作为该类成员的程序实体能直接访问该类的非public成员,这些程序实体称为该类的友元。
              • 友元是数据保护和数据访问效率之间的一种折衷方案。
            • 友元需要在类中用friend显式指出,它们可以是 全局函数 其它类的所有成员函数 其它类的某个成员函数 例如:
              📌
              关于友元的几点说明
              友元不是一个类的成员。 友元关系具有不对称性。例如:假设B是A的友元,如果没有显式指出A是B的友元,则A不是B的友元。 友元也不具有传递性。例如:假设C是B的友元、B是A的友元,如果没有显式指出C是A的友元,则C不是A的友元。
              • 例子:矩阵与向量

                类作为模块

                什么是模块

                • 模块
                  • 从物理上对程序中定义的实体进行分组,是可以单独编写和编译的程序单位。
                  • 模块化是组织和管理大型程序的一个重要手段。
                • 一个模块包含接口和实现两部分:
                  • 接口:是指在模块中定义的、可以被其它模块使用的一些程序实体的声明描述。
                  • 实现:是指在模块中定义的所有程序实体的具体实现描述
                • C语言程序的模块构成:
                  • 接口:包含被外界使用的类型和常量的定义以及函数和全局变量的声明。(放在.h文件中)
                  • 实现:包含本模块中所有的类型、常量、全局变量和函数的定义。(放在.c文件中)

                如何划分模块

                • 划分模块的基本准则:
                  • 内聚性最大:模块内的各实体之间联系紧密。
                  • 耦合度最小:模块间的各实体之间关联较少。
                  • 便于程序的设计、理解和维护,能够保证程序的正确性。
                • 过程式程序(C语言支持的)的模块划分通常是基于子程序(函数),把共同完成某独立功能的或使用相同数据的子程序及相关的实体放在一起构成模块。
                  • 缺点是模块边界模糊,有时无法确定一个子程序应该放在哪个模块中:
                  • 一个子程序可能参与几个独立功能。
                  • 一个子程序可能使用多个数据集。

                类作为模块

                • 在面向对象程序中,类是一个自然的模块划分单位,一个类构成一个模块,模块边界比较清晰。
                • C++程序的一个模块由两部分构成:
                  • 接口:类的定义,存放在一个.h文件中
                  • 实现:类的实现(包括类的定义和在类外定义的成员函数),存放在一个.cpp文件中。

                良好的面向对象程序设计风格

                • 结构化程序设计为过程式程序设计提供了一种良好的风格指南,它要求每个程序单位都应该具有“单入口/单出口”性质,使得各程序单位相对独立(耦合度较小),具体体现为使用:
                  • 不带goto的顺序、分支和循环流程控制
                  • 子程序
                • 良好的面向对象程序设计风格是:
                  • 减少类之间的关联度(耦合度)!
                  • 要减少类间的关联度,可以对类中成员函数能访问的其它类/对象的集合作一定的限制,尽量使该集合为最小
                📌
                上述要求被称为Demeter法则。

                Law of Demeter

                • 一个类的成员函数
                  • 除了能访问自身类结构的直接子结构(本类的数据成员)外,不能以任何方式依赖于任何其它类的结构
                  • 只应向某个有限集合中的对象发送消息。
                • 核心思想:“仅与你的直接朋友交谈!”
                • Demeter法则有两种表达形式:
                  • 类表达形式:一个类中的成员函数能访问(向其发消息)的对象所属类的集合。适合于静态类型的面向对象语言(如:C++),它可以在编译时刻检查程序是否满足法则。
                  • 对象表达形式:一个类中的成员函数能访问(向其发消息)的对象的集合。适合于动态类型的面向对象语言(如:Smalltalk),它需要在运行时刻检查程序是否满足法则。