FreeCAD源码分析:Externsion机制
本文分析FreeCAD中Extension机制的实现。注1限于研究水平文中分析难免有不当之处欢迎批评指正。注2本文档将不定期更新。一、机制概览FreeCAD 的文档对象App::DocumentObject需要同时支持几何、分组、链接、附件、模式、求解器、可见性等能力。若把所有能力都放进一个继承层次会造成类数量爆炸、基类臃肿和功能耦合。Extension 机制把“可选能力”拆成可组合的扩展对象宿主对象负责生命周期、属性和调度扩展对象负责一组相对独立的领域行为。Extension 是一种对象级组合composition机制不是动态库插件加载机制也不是 C 多继承的替代语法。一个宿主可以同时挂载多个扩展扩展通过ExtensionContainer被统一注册、查找、遍历并参与属性访问、序列化和文档对象生命周期。典型关系如下App::DocumentObject └─继承/包含 ExtensionContainer 的能力 ├─ GroupExtension ├─ LinkBaseExtension ├─ AttachExtension └─ 其他 DocumentObjectExtension 派生类二、设计动机与目标2.1 解决继承树膨胀某个对象可能既是可分组对象又支持链接和附件。用继承表达所有组合会产生大量“组合类”扩展允许按需挂载能力新增能力通常只需新增一个 Extension 类。2.2 保持核心对象稳定DocumentObject保留通用的名称、标签、表达式、可见性、文档归属等基础职责领域特性放在独立扩展中降低修改核心类带来的回归风险也方便不同工作台复用同一扩展。2.3 统一 App/Gui/Python 边界扩展既可承载数据和计算行为也可提供 Python 包装对象DocumentObjectExtension还能声明对应的 ViewProvider Extension 类型。这样应用层能力可以与 GUI 表现、Python 自动化保持一致的扩展点。2.4 让属性和文件格式可组合扩展的属性通过宿主的PropertyContainer接口暴露用户看到的属性表不需要知道属性来自哪个扩展。ExtensionContainer还负责扩展数据的保存与恢复使扩展状态能随文档持久化。三、核心设计原理3.1 宿主、容器、扩展三层模型宿主Host通常是DocumentObject拥有对象身份、文档关系和公共属性。容器ContainerApp::ExtensionContainer维护扩展映射并把扩展属性聚合到宿主的属性接口。扩展ExtensionApp::Extension派生类保存可选能力扩展通过getExtendedContainer()访问宿主。ExtensionContainer内部以Base::Type为键保存Extension*因此一个宿主可按类型精确查找也可按基类查找所有派生扩展。3.2 FreeCAD 类型系统而非 RTTIExtension使用EXTENSION_TYPESYSTEM_*宏注册 FreeCADBase::Type。派生类在init()中调用initExtensionSubclass()建立父子类型关系和工厂函数。容器的getExtension()、hasExtension()支持按类型、名称和“是否允许派生类型”查询。这种类型系统同时服务于 C、Python 包装和文档恢复序列化数据中的扩展类型名可以映射回已注册的类型并创建对象。3.3 组合属性与属性链扩展使用EXTENSION_PROPERTY_HEADER/EXTENSION_PROPERTY_SOURCE声明属性元数据。扩展初始化时Extension::initExtension()会遍历扩展属性把每个属性的容器设置为宿主然后调用registerExtension()。因此扩展属性可以通过宿主的getPropertyByName()、getPropertyList()、getPropertyMap()等接口访问。扩展属性元数据通过PropertyData::parentPropertyData形成继承链既保留扩展自身属性也能查到父扩展属性。3.4 运行时委托而不是隐式魔法DocumentObject在执行、恢复、设置文档、建立/拆除对象等阶段显式遍历getExtensionsDerivedFromTypeDocumentObjectExtension()逐个调用对应回调。扩展只在实现了相关能力时覆盖虚函数默认实现保持空操作或返回成功。四、核心组件4.1App::Extension文件src/App/Extension.h/.cpp职责包括保存扩展类型Base::Type与宿主指针initExtension()完成属性绑定和注册通过name()、getExtensionTypeId()提供类型信息将扩展属性转发给PropertyData通过getExtensionPyObject()延迟创建 Python 包装对象提供属性名称/类型变更的兼容性回调。未设置扩展类型时初始化和取名会抛出Base::RuntimeError这是防止扩展以不完整状态进入容器的保护。4.2App::ExtensionContainer文件src/App/ExtensionContainer.h/.cpp它是扩展的注册表和属性聚合器主要接口包括registerExtension(type, ext)注册扩展hasExtension()/getExtension()按类型或名称查询getExtensionsDerivedFrom()取得某基类下的所有扩展extensionBegin()/extensionEnd()遍历扩展getPropertyByName()、getPropertyList()等聚合扩展属性Save()/Restore()保存和恢复扩展数据。注册时会校验扩展的类型关系和宿主关系避免把不属于该容器的对象登记进去。4.3App::DocumentObjectExtension文件src/App/DocumentObjectExtension.h/.cpp这是面向文档对象的专用基类提供getExtendedObject()取得DocumentObject宿主extensionMustExecute()/extensionExecute()参与重计算onExtendedSettingDocument()对象设置文档后回调onExtendedDocumentRestored()从文件完整恢复后回调onExtendedSetupObject()/onExtendedUnsetupObject()创建和移除阶段回调子对象、链接对象和元素可见性的扩展点getViewProviderExtensionName()声明自动附着的 GUI 扩展类型。4.4DocumentObject中的调度点DocumentObject::executeExtensions()会收集所有DocumentObjectExtension派生扩展并调用extensionExecute()对象重计算流程还会根据扩展的extensionMustExecute()判断是否需要执行。文档设置、恢复、对象建立和拆除等流程也在DocumentObject.cpp中统一转发到扩展回调。五、关键流程5.1 类型注册程序启动/模块初始化FreeCAD 初始化App::Extension基类类型。各模块调用派生扩展的init()。宏生成的代码通过Base::Type::createType()注册名称、父类型和创建函数。后续可按类型名称恢复或创建扩展。5.2 创建并挂载扩展典型 C 过程可概括为autoextnewMyExtension;ext-initExtensionType(MyExtension::getExtensionClassTypeId());ext-initExtension(host);// 绑定属性、保存宿主、注册到容器实际项目通常在对象构造或工厂函数中完成创建并由宿主/容器负责生命周期。initExtension()会先设置属性容器再登记到容器映射类型未初始化时会直接报错。5.3 属性访问与变更用户或脚本通过宿主名称访问属性。ExtensionContainer在自身属性和扩展属性中查找。找到扩展属性后属性的容器仍指向宿主因此变更通知、事务和文档脏标记沿用宿主机制。扩展可在自身onChanged()或宿主相关回调中处理变化。5.4 重计算文档将对象加入重计算队列。DocumentObject判断自身逻辑以及扩展是否需要执行。executeExtensions()按注册的扩展集合调用extensionExecute()。任一扩展返回错误对象时重计算结果带出错误原因返回DocumentObject::StdReturn表示成功。5.5 保存与恢复保存时ExtensionContainer::Save()将扩展数据写入对象 XML并记录扩展类型。恢复时容器读取类型名查找已注册类型创建或定位对应扩展再调用扩展属性的Restore()。未知扩展或版本变化可通过extensionHandleChangedPropertyName()/extensionHandleChangedPropertyType()参与兼容处理。5.6 Python 访问第一次请求扩展的 Python 对象时getExtensionPyObject()延迟创建包装对象并缓存引用。C 扩展与ExtensionPython派生扩展使用不同的 Python 包装类扩展析构时会使包装对象失效避免 Python 仍持有已销毁 C 对象。六、应用场景分组能力GroupExtension为对象提供组成员管理和树结构行为。链接能力LinkBaseExtension统一处理被链接对象、递归解析和变换矩阵。附件/定位Part 工作台的AttachExtension为对象提供支持面、偏移和坐标系相关能力。几何或显示辅助几何、预览、纹理、网格缩略图等能力可独立为扩展避免污染基础对象。求解器/工作台专用能力Sketcher、FEM、TechDraw 等模块通过各自 Extension 增加执行、数据或显示行为。Python 原型和自动化Python 扩展可快速给对象增加属性和行为并通过同一容器机制被 C/Python 查询。兼容旧文件扩展自带属性和恢复回调适合在不改变宿主主类的情况下演进文件格式。参考资料src/App/Extension.h、src/App/Extension.cpp基类、类型注册、属性转发、Python 包装。src/App/ExtensionContainer.h、src/App/ExtensionContainer.cpp注册表、查找、属性聚合、序列化。src/App/DocumentObjectExtension.h、src/App/DocumentObjectExtension.cpp文档对象生命周期与执行回调。src/App/DocumentObject.h、src/App/DocumentObject.cpp扩展容器继承关系、重计算和生命周期调度。src/App/GroupExtension.*、src/App/LinkBaseExtension.*、src/Mod/Part/App/AttachExtension.*典型应用实现。src/App/*ExtensionPyImp.cpp、*.pyiPython 包装和类型提示。

相关新闻

C语言数据结构笔记:动态数组

C语言数据结构笔记:动态数组

前言 本文面向编程零基础小白,用生活化案例通俗讲解C语言中动态数组核心概念、组成要素与完整实操流程,手把手演示动态数组的完整可运行代码示例。 一、核心概念 指针变量 指的是可以储存某个 内存地址 的变量。一般来说,指针变量并不储存…

2026/10/11 1:54:43 阅读更多 →
4核8G云服务器部署GitLab内存耗尽解决方案

4核8G云服务器部署GitLab内存耗尽解决方案

文章目录前言原因解决方案创建Swap分区修改配置文件前言 阿里云官方给出的方案是4核8G为最小部署Gitlab的配置,实际上配置完成后,云服务器的内存资源几乎被耗尽,本文将会给出对应的解决方案 原因 可以先通过 free -h 查看内存占用情况&…

2026/10/11 1:54:43 阅读更多 →
接口自动化 登录实现 pymysql

接口自动化 登录实现 pymysql

接口自动化:url:请求地址params:用于提交键值对数据,在请求行提交,适用于get和delete请求data:用于提交JSON数据,在请求提交,适用于POST和PUT请求json:用于提交JSON数据&…

2026/10/11 1:54:43 阅读更多 →

最新新闻

ArcGIS属性表字段添加与编辑实战:类型选择、计算器及维护指南

ArcGIS属性表字段添加与编辑实战:类型选择、计算器及维护指南

1. 字段类型没选对,后面全是坑:先把数据需求想明白前天帮同事处理一份小区地块数据入库,忙活半小时后发现面积字段精度对不上,明明算好是123.45平方米,属性表里却挂着123.450000001。我问他当时添加字段选了什么类型&a…

2026/10/11 2:43:12 阅读更多 →
n8n从Docker部署到生产环境的高频踩坑与工作流排查实践

n8n从Docker部署到生产环境的高频踩坑与工作流排查实践

前端联调群里有人发了一张执行列表截图,工作流显示成功,但业务方就是收不到数据,大家在群里排查了半天,最后发现是Webhook响应节点没接对。这类问题在n8n工作流里实在太常见了——我自己从第一次用Docker部署n8n,到把它…

2026/10/11 2:43:12 阅读更多 →
本地知识库检索系统搭建:混合检索与调优实战

本地知识库检索系统搭建:混合检索与调优实战

先把话说在前面:这个项目我到现在都没给它起一个正经名字,电脑里的文件夹写着“知识库项目”,手机备忘录里叫“文档管家”,所以下面的正文,我就叫它“无标题”项目。事情是这样的——我手头的文档越来越多,…

2026/10/11 2:43:12 阅读更多 →
局域网大文件秒传实战指南:四种方案避开云盘U盘

局域网大文件秒传实战指南:四种方案避开云盘U盘

我真正意识到局域网传文件有多香,是去年帮家里人备份手机相册那次。导了半天U盘,电脑不认盘,手机OTG转换器又找不到,最后折腾到晚上十点多才把一万多张照片拷出来。后来换成局域网直传,同样一批照片,满打满…

2026/10/11 2:43:12 阅读更多 →
古汉语NLP实践:用Jiayan搞定文言文分词断句与词性标注

古汉语NLP实践:用Jiayan搞定文言文分词断句与词性标注

简介:Jiayan(甲言)是一款面向古代汉语(文言文/古文)的NLP工具包,旨在弥补通用自然语言处理工具集中于现代汉语、对古汉语支持不足的短板,为古汉语学者、语言爱好者及相关研究者提供分词、词性标…

2026/10/11 2:43:12 阅读更多 →
微信iPad协议最新版授权端:登录态模拟与长连接工程实践

微信iPad协议最新版授权端:登录态模拟与长连接工程实践

简介:这份资源面向需要在iPad设备上稳定使用微信服务的用户,以及关注iPad协议授权机制的开发者,提供更新至最新状态的客户端打包文件。压缩包共20个文件,约9.05MB,以ec易语言模块、dll动态库、txt说明文档、silk音频、…

2026/10/11 2:42:12 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →