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("槽") 方法。

相关推荐
ModestCoder_1 小时前
windows/ubuntu解决挂梯子但是codex reconnecting五次的问题
linux·windows·ubuntu
禹凕1 小时前
Linux基础——环境
linux·运维·服务器·ubuntu
好好风格1 小时前
【一行代码】查看本机公网 IP
linux·命令行
落羽的落羽3 小时前
【算法札记】练习 | Week5
linux·服务器·c++·人工智能·计算机网络·算法·哈希算法
Evan_ZGYF丶3 小时前
【开发工具】【perf】Linux下性能分析工具(perf)的使用
linux·嵌入式·开发工具·perf
AC赳赳老秦4 小时前
OpenClaw任务复盘自动化:统计每日完成工作、遗留问题,优化工作节奏
java·大数据·linux·运维·服务器·数据库·openclaw
kaoa0004 小时前
Linux入门攻坚——79、XEN虚拟化-2
linux·运维·开发语言
AOwhisky4 小时前
学习自测(MySQL系列第一期、第二期)
linux·运维·数据库·学习·mysql·云计算
提伯斯6464 小时前
Jetson_Pixhawk局域网UDP连接QGC
linux·网络·嵌入式硬件·网络协议·udp·jetson