跳转至

Composition⚓︎

885 个字 44 行代码 预计阅读时间 5 分钟

组合(composition):从已存在的对象中构造新的对象,即复用已有的实现。

  • 包含 (inclusion) 方式:

    • 完全(fully) 包含
      • 构造函数和析构函数会被自动调用
    • 通过引用(reference) 包含
      • 需要手动初始化和销毁对象
      • 应用场景:逻辑关系并不是完全的、程序开始时还不清楚对象大小、需要在运行时分配 / 连接资源 ...
      • 其他 OOP 语言只能采用这种方式
  • 嵌入对象 (embedded objects)

    • 所有的嵌入对象都被初始化了
      • 当不提供参数时,默认的构造函数(或者自己创建的构造函数)就会被调用
    • 构造函数可以有初始化列表
      • 任意数量的对象,用逗号分隔
      • 可选的
      • 提供给子构造函数的参数
    • 析构函数会被自动调用
    • public vs private

      • 声明嵌入对象为私有的(private)是很常见的
        • 它们是底层实现的一部分
        • 新类只有旧类的部分公共接口
      • 如果想要让子对象的整个公共接口对新对象而言都是可用的话,那么就声明为公有的(public
      class SavingsAccount {
          public:
              Person m_saver; ...
      };    // assume Person class has set_name()
      SavingsAccount account;
      account.m_saver.set_name("Fred");
      
  • 模块化(modularization):将整体划分为多个良好定义的部分的过程,每个部分可以独立地被建立和检验,并且能以定义良好的方式与之互动。

Initialization List⚓︎

关于初始化列表(initialization list):

  • 能够初始化任意类型的数据
    • 伪构造函数调用内建函数
    • 没有必要在构造函数体内执行赋值语句
  • 初始化的顺序是生命的顺序,并非在列表中的顺序
    • 并且以相反的顺序被销毁
  • 比较初始化和赋值:

    // Initialization(before constructor)
    Student::Student(string s):name(s) {}
    
    // Assignment(inside constructor)
    Student::Student(string s) { name = s; }
    

Namespace⚓︎

命名空间(namespace):

  • 一种对类、函数和变量等的逻辑上的分组
  • 命名空间就是一个类似类的作用域
  • 当仅需要命名封装时,更倾向于这种方法
  • 作用:

    • 控制名称:限制名称的作用域
    • 避免名称冲突
  • 定义:放在头文件中

    // Mylib.h
    namespace MyLib {
        void foo();
        class Cat {
        public:
            void Meow();
        };
    }
    
  • 定义命名空间的函数:使用常规的作用域来实现命名空间的函数

    // MyLib.cpp
    #include "MyLib.h"
    void MyLib::foo() { cout << "foo\n"; }
    void MyLib::Cat::Meow() { cout << "meow\n"; }
    
  • 使用来自命名空间的名称:使用作用域解析式从命名空间中获取名称,但这样做比较麻烦

    #include "MyLib.h"
    void main() {
        MyLib::foo();
        MyLib::Cat c;
        c.Meow();
    }
    
  • 使用声明

    • 为名称引入局部同义词
    • 消除冗余的作用域修饰法
    void main() {
        using MyLib::foo;
        using MyLib::Cat;
        foo();
        Cat c;
        c.Meow();
    }
    
  • 使用指示符

    • 这样使命名空间内所有的名称均可用
    • 带来了不少便利
    void main() {
        using namespace std;
        using namespace MyLib;
        foo();
        Cat c;
        c.Meow();
        cout << "hello" << endl;
    }
    
    • 但这样可能会带来潜在的歧义(ambiguities) 问题。所以遇到不同的命名空间出现相同名称时,还是要用作用域解析式
  • 别名

    • 命名空间的名称过短可能会导致冲突
    • 名称过长则给使用带来不便
    • 所以使用别名来创建实用的名称
    • 别名还可以用在版本库中
  • 命名空间组合

    • 可以使用别的命名空间中的名称组合成新的命名空间
    • 使用声明可以解决潜在的冲突
    • 显式定义的函数占据更高的优先级
  • 命名空间选择

    • 通过选择别的命名空间中的特征来组合成新的命名空间
    • 可以选择需要的名称而不是全部
  • 命名空间是开放的:多个命名空间声明可以被加到相同的命名空间,且命名空间可以分散在多个文件中

评论区

如果大家有什么问题或想法,欢迎在下方留言~