C++软件架构设计思路

第1章 MFC框架的理解

1.1 动态创建类

(1)背景------传统方式的局限

传统 C++ 创建对象必须 #include 头文件、手动 new,类型在编译期写死。团队协作时,每新增一个类,调用方代码就要跟着改,耦合严重。

(2)框架设计------自实现 一套运行时类型识别(RTTI)

C++ 内置 RTTI 只能做类型判断,无法按字符串创建对象。该框架在此基础上扩展,通过四个核心组件实现了完整的运行时类型识别与动态创建能力:

  • 顶级基类 LObject :所有类的公共祖先,提供 isKindOfgetRuntimeClass 等统一接口
  • CRuntimeClass 结构体:每个类对应一个实例,存储类名、对象大小、schema、工厂函数指针、父类指针,是 RTTI 的元信息载体
  • 全局单向链表 :以 m_pFirstClass 为链表头,将所有注册类的元信息串联起来,是运行时查找的基础
  • 两个宏DECLARE_DYNAMIC 负责在 .h 里声明元信息结构体、虚函数、工厂函数;IMPLEMENT_DYNAMIC 负责在 .cpp 里填充元信息、生成静态注册器,程序启动时自动将本类插入全局链表

(3)带来的价值

框架将每个类变成自给自足的独立单元 ------继承 LObject、挂上两个宏,类就完成了自我注册,与其他任何类没有编译期依赖。团队协作时各写各的,互不干扰:

总节:

  1. 传统方式:调用方自己写 new,必须包含头文件,类型编译期写死。
  2. 该框架:通过两个宏 + 全局单向链表 + 顶级基类 LObject
  3. 每个类继承 LObject,通过两个宏将自身元信息(类名、大小、schema、工厂函数指针、父类指针)在程序启动时自动注册进全局链表。
  4. 使用时通过字符串查链表找到对应节点,再调用节点里存的工厂函数指针,由框架内部的 new 完成创建,调用方无需包含头文件,也无需感知具体类型。



该框架是对 C++ 内置 RTTI 的超集实现------用两个宏 + 全局单向链表 + 顶级基类,在编译期埋下元信息,运行期实现按字符串动态创建对象,解决了内置 RTTI 做不到的运行时对象工厂问题,同时从根本上消除了团队协作中的编译期耦合。

1.2 定时器

借鉴LibUV源码,基于最小堆(完全二叉树) + 就绪队列的定时器实现。

(1)初始化阶段

  1. 获取当前系统时间戳 → 存入 loop->time;
  2. 初始化空的最小堆 timer_heap;
  3. 初始化空的就绪队列 timer_ready;
  4. 初始化 timer_counter = 0;

(2)启动定时器阶段

timer_start(&timer_a, task_a, 3000, 2000);

  1. 计算到期时间戳:timeout = loop->time + 3000
  2. 分配启动序号:start_id = timer_counter++
  3. 插入最小堆(按 timeout 排序,timeout 相同时按 start_id 排序)

启动多个定时器后,堆自动排好序:

堆:13000, 15000, 18000, 20000 ← 堆顶最早到期

(3)事件循环阶段(每次调用 timer_run()

1、更新时间;

loop->time = now_ms(); // 获取最新系统时间戳

  1. 从最小堆堆顶取出到期的定时器,放置到等待处理的等待队列中。再次判断堆顶是否还有到期时间的定时器。有的话再次取出放置到等待队列中。
cpp 复制代码
// 阶段1:从堆摘到队列
while (堆顶到期) {
    handle = 摘堆顶();
    放入就绪队列;  // 此时还没执行回调,也还没放回堆
}

// 阶段2:从队列取出执行
while (队列不为空) {
    handle = 取出队首();
    handle->cb(handle);  // 先执行回调
    
    if (handle->repeat > 0) {
        // 回调执行完了,才重新放回堆
        handle->timeout = loop->time + handle->repeat;
        插入堆中;
    }
}
  1. 队列执行完回调,重新放回最小堆中。

  2. 依次循环。

1.3 信号与槽

C++ Signal/Slot Library (sigslot) - Browse Files at SourceForge.net

sigslot的原理其实非常简单,它就是一个变化的观察者模式。观察者模式如下所示:

观察者模式,首先让 Observer("观察者")对象 注册到 Subject("被观察者") 对象中。当 Subject 状态发生变化时,遍历所有注册到自己的 Observer 对象,并调用它们的 notify方法。

sigslot与观察者模式类似,它使用signal("信号")和slot("槽"),区别在于 signal 主动连接自己感兴趣的类及其方法,将它们保存到自己的列表中。当发射信号时,它遍历所有的连接,调用 slot("槽") 方法。

相关推荐
Web3探索者1 天前
可视化服务器管理和传统命令行区别是什么?新手教程:Linux 运维到底该用图形界面还是 SSH 命令行?
linux·ssh
zylyehuo1 天前
Linux系统中网线与USB网络共享冲突
linux
Sokach10153 天前
Linux Shell 脚本从零到能用:一个新手的一天学习总结
linux
AlfredZhao3 天前
Docker 容器时区不对,`timedatectl` 不存在怎么办?
linux·timezone
zzzzzz3105 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
XIAOHEZIcode5 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
A小辣椒6 天前
TShark:Wireshark CLI 功能
linux
A小辣椒7 天前
TShark:基础知识
linux
AlfredZhao7 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao7 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi