尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

F´ (F Prime) 集合抽象基类 SetBase 全面解析:接口设计、迭代器模型与具体实现

F´ (F Prime) 集合抽象基类 SetBase 全面解析:接口设计、迭代器模型与具体实现 F´ (F Prime) 集合抽象基类 SetBase 全面解析接口设计、迭代器模型与具体实现【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprimeSetBase是 F´ 飞行软件与嵌入式系统框架中集合数据结构的抽象基类模板定义于Fw/DataStructures模块为所有集合实现如基于数组的ArraySet、基于红黑树的RedBlackTreeSet提供统一的多态接口。本文将以 SetBase.md 为核心骨架结合 SetBase.hpp 源码实现、SetConstIterator.hpp 迭代器机制以及 ArraySetTest.cpp 测试用例完整讲解其模板参数、继承体系、六个纯虚/公共接口的语义与示例并深入剖析copyDataFrom的拷贝算法与底层委托实现帮助读者在嵌入式环境中正确使用和扩展 F´ 集合容器。一、SetBase 在 F´ 数据结构体系中的定位F´ 的Fw/DataStructures模块采用接口抽象 具体实现的两层架构顶层是一组抽象基类SizedContainer、SetBase、MapBase、StackBase等底层则是持有实际存储的实现类。SetBase正是集合set这一支线的抽象层。SetBaseT公开继承自抽象容器基类SizedContainer后者定义了所有有容量限制的容器共有的四个接口virtual void clear() 0清空容器virtual FwSizeType getCapacity() const 0返回容器容量最大可存储元素数virtual FwSizeType getSize() const 0返回当前元素个数isEmpty()/isFull()由getSize()与getCapacity()派生的便捷查询非虚函数。这意味着任何SetBase的派生类都天然具备查询大小、容量、判断空/满的能力。集合的语义是元素唯一同一元素最多存在一份插入已存在的元素不会产生重复项。在类族结构上SetBase与具体实现类的关系可概括为SizedContainer抽象基类容量/大小/清空 ↑ 公开继承 SetBaseT抽象基类集合语义6 个成员接口 ↑ 公开继承 ┌─────────────┴──────────────┐ ArraySetT, C RedBlackTreeSetT, C 内部数组存储 内部红黑树存储 委托 ExternalArraySet 委托 ExternalRedBlackTreeSet二、模板参数与基类2.1 模板参数SetBase是一个类模板定义如下Kind名称用途typenameT集合中元素的类型模板形参T在接口层面贯穿始终find、insert、remove三个成员函数均以const T作为参数迭代器ConstIterator也以T为模板参数实例化。2.2 基类SetBaseT公开派生自SizedContainer因此在 SetBase.hpp 中可见template typename T class SetBase : public SizedContainer {所有派生类必须实现SizedContainer的纯虚函数clear、getCapacity、getSize才能实例化。三、设计决策禁用的拷贝操作SetBase将拷贝构造函数和拷贝赋值运算符声明为private且 delete从源头上禁止基类拷贝private: //! Copy constructor deleted in the base class SetBase(const SetBaseT) delete; //! operator deleted in the base class //! Behavior depends on the implementation //! We avoid virtual user-defined operators SetBaseT operator(const SetBaseT) delete;源码注释揭示了两个关键设计原因行为取决于具体实现不同集合实现数组 vs 红黑树的拷贝语义不同基类无法给出统一实现避免虚赋值运算符C 中定义virtual operator会导致语义混乱参数类型协变问题因此基类干脆禁止拷贝将拷贝能力下放到具体派生类各自实现如ArraySet提供自己的拷贝构造函数与operator见下文第六节。四、公共类型ConstIteratorSetBase定义一个公共类型别名名称定义ConstIteratorSetConstIteratorT的别名using ConstIterator SetConstIteratorT;SetConstIterator是专为集合设计的只读const迭代器迭代顺序未定义The iteration order is not specified这给了不同底层实现数组、红黑树充分的存储自由度。它支持operator、operator、operator!、前缀/后缀operator、解引用operator*、箭头operator-以及isInRange()范围检查。从源码看SetConstIterator.hpp 内部通过一个union Impl同时容纳数组迭代器ArrayIterator与红黑树迭代器RedBlackTreeIterator并借助SetOrMapImplConstIterator的implKind()区分当前实现类型——这是一种嵌入式友好的类型擦除手法用一个统一类型包装两种底层迭代器从而让上层SetBase接口可以返回单一类型ConstIterator。解引用时它最终调用getEntry().getKeyOrElement()返回元素本身SetConstIterator.hpp。五、受保护的构造与析构SetBase的构造函数为protected因此它只能作为基类被继承不能直接实例化protected: //! Zero-argument constructor SetBase() : SizedContainer() {} //! Destructor virtual ~SetBase() default;零参数构造函数使用成员默认初始化内部仅转发到SizedContainer()虚析构函数 default但声明为virtual——这是多态销毁的关键保证通过SetBase*删除派生类对象时能正确调用派生类析构函数避免内存泄漏。六、核心公共成员函数详解SetBase提供六个公共成员函数其中五个为纯虚函数begin、end、find、insert、remove由派生类实现copyDataFrom为基类内联提供的非虚通用算法。下面逐一解析其语义与用法示例。6.1 begin获取起始迭代器virtual ConstIterator begin() const 0返回指向集合第一个元素的ConstIterator。具体第一个元素是谁由实现决定数组实现为下标 0 的元素红黑树实现为最左节点。示例void f(SetBaseU32 set) { set.clear(); // Insert an element in the set const auto status set.insert(42); ASSERT_EQ(status, Fw::Success::SUCCESS); // Get a set const iterator object auto it set.begin(); // Use the iterator to access the element ASSERT_EQ(*it, 42); }6.2 copyDataFrom跨集合数据拷贝这是SetBase中唯一在基类直接实现的非虚函数见 SetBase.hpp其算法步骤为若set ! this即目标不是自身继续执行调用clear()清空目标集合令size min(set.getSize(), this-getCapacity())——取源集合大小与目标容量中的较小值防止目标集合溢出令it set.begin()对i从 0 到size-1循环insert(*it)插入当前元素断言status Success::SUCCESS因为已按容量截断插入必然成功然后it前进。void copyDataFrom(const SetBaseT set) { if (set ! this) { this-clear(); const FwSizeType size FW_MIN(set.getSize(), this-getCapacity()); auto it set.begin(); for (FwSizeType i 0; i size; i) { const auto status this-insert(*it); FW_ASSERT(status Success::SUCCESS, static_castFwAssertArgType(status)); it; } } }注意源码中的实现细节FW_MIN宏与FW_ASSERT断言是 F´ 框架的惯用工具。容量截断语义是该方法的重要行为特征当目标集合容量小于源集合大小时只拷贝放得下的前缀部分超出部分被丢弃——这也解释了为什么copyDataFrom必须先从set.begin()顺序遍历。示例void f(SetBaseU32 s1, SetBaseU32 s2) { s1.clear(); // Insert an entry const auto status s1.insert(42); ASSERT_EQ(status, Success::SUCCESS); ASSERT_EQ(s1.getSize(), 1); s2.clear(); ASSERT_EQ(s2.getSize(), 0); s2.copyDataFrom(s1); ASSERT_EQ(s2.getSize(), 1); }6.3 end获取结束迭代器virtual ConstIterator end() const 0返回越过末尾past-the-end的哨兵迭代器用于循环终止判断。示例void f(SetBaseU32 set) { set.clear(); // Insert an element in the set auto status set.insert(42); ASSERT_EQ(status, Fw::Success::SUCCESS); // Get a set const iterator object auto iter set.begin(); // Check that iter is not at the end ASSERT_NE(iter, set.end()); // Increment iter iter; // Check that iter is at the end ASSERT_EQ(iter, set.end()); }6.4 find查找元素virtual Success find(const T element) const 0若集合中存在元素值为element的条目e返回SUCCESS否则返回FAILURE。返回值类型Success是 F´ 的Fw/Types/SuccessEnumAc.hpp中定义的状态枚举接口通过头文件包含引入见 SetBase.hpp。该函数为const不会修改集合。示例void f(SetBaseU32 set) { set.clear(); auto status set.find(42); ASSERT_EQ(status, Success::FAILURE); status set.insert(42); ASSERT_EQ(status, Success::SUCCESS); status set.find(42); ASSERT_EQ(status, Success::SUCCESS); }6.5 insert插入元素virtual Success insert(const T element) 0三条语义规则若已存在元素值相同的条目e返回SUCCESS重复插入被幂等地接受不产生重复项否则若集合未满新增条目并返回SUCCESS否则集合已满返回FAILURE。这条语义决定了集合的去重特性insert不会抛出异常或断言失败而是用返回值向调用方报告容量状态非常适合无异常机制的嵌入式环境。示例void f(SetBaseU32 set) { set.clear(); auto size set.getSize(); ASSERT_EQ(size, 0); const auto status set.insert(42); ASSERT_EQ(status, Success::SUCCESS); size set.getSize(); ASSERT_EQ(size, 1); }6.6 remove移除元素virtual Success remove(const T element) 0若集合中存在元素值为element的条目e移除该条目并返回SUCCESS否则返回FAILURE元素不存在时移除是无害且明确告知的操作。示例void f(SetBaseU32 set) { set.clear(); auto size set.getSize(); ASSERT_EQ(size, 0); auto status set.insert(0); ASSERT_EQ(status, Success::SUCCESS); size set.getSize(); ASSERT_EQ(size, 1); // Element does not exist status set.remove(42); ASSERT_EQ(status, Success::FAILURE); ASSERT_EQ(size, 1); // Key exists status set.remove(0); ASSERT_EQ(status, Success::SUCCESS); ASSERT_EQ(size, 0); }七、具体实现类ArraySet 与 RedBlackTreeSetSetBase是抽象基类实际使用需实例化具体实现。F´ 在Fw/DataStructures中提供了两个典型实现7.1 ArraySet数组存储固定容量ArraySetT, C是final类模板T为元素类型、C为编译期容量静态断言C 0。其内部持有两个成员ExternalArraySetT m_extSet外部数组集合实现Entry[C] m_entries提供底层内存的条目数组。构造函数将m_extSet初始化为ExternalArraySetT(m_entries, C)——即把用户在此为ArraySet提供的静态数组作为后备存储实现内部存储但接口委托的封装模式。所有begin/end/find/insert/remove/getCapacity/getSize/clear均一行转发给m_extSet例如insert返回m_extSet.insert(element)。using Set ArraySetU32, 10; Set set; const auto status set.insert(42); ASSERT_EQ(set.getSize(), 1); ASSERT_EQ(set.getCapacity(), 10);ArraySet还提供了自己的拷贝构造函数与operator不同于基类的删除策略拷贝构造会先用本对象的m_entries初始化m_extSet再赋值operator返回m_extSet.copyDataFrom(set)的结果。7.2 RedBlackTreeSet红黑树存储元素有序RedBlackTreeSetT, C是另一final实现结构上与ArraySet完全对称但底层委托给ExternalRedBlackTreeSetT元素按红黑树有序组织查找、插入、删除均为对数复杂度。由于SetBase的迭代顺序本就未指定上层代码无需关心遍历次序差异。两个实现的接口签名与SetBase完全一致因此面向SetBase接口编写的应用代码可以在两种实现之间无缝切换这正是抽象基类的价值所在。八、测试与验证行为契约的落地F´ 为集合族提供了详尽的单元测试测试文件位于Fw/DataStructures/test/ut/其中 ArraySetTest.cpp 覆盖了ArraySet的完整行为契约ZeroArgConstructor验证容量等于State::capacity、初始大小为 0CopyConstructor/CopyAssignmentOperator验证拷贝后大小与元素可查找性CopyDataFrom覆盖三种容量关系——源小于目标容量、等于目标容量、大于目标容量验证容量截断Clear/Find/FindExisting/InsertExisting/InsertFull/InsertNotFull/Remove/RemoveExisting以 STest 场景库逐项验证接口语义Random随机操作 1000 次验证实现的鲁棒性。对应的RedBlackTreeSetTest.cpp、ExternalArraySetTest.cpp等文件对红黑树版本与外部存储版本执行同样的验证。这些测试用例尤其是CopyDataFrom的三种容量关系测试直接印证了第六节所述copyDataFrom的FW_MIN截断语义。九、使用建议与注意事项通过基类接口编程业务代码尽量以SetBaseT或const SetBaseT作为参数如文档示例所示底层实现可自由切换ArraySet与RedBlackTreeSet。容量与失败处理嵌入式环境通常禁用异常务必检查insert的FAILURE返回值集合已满并预先用getCapacity()/isFull()判断容量。迭代器的只读与失效ConstIterator只读且不可用于修改集合文档明确建议不要在通过迭代器指向集合后更新集合再使用该迭代器operator*与operator-在迭代器越界时会触发断言失败。拷贝语义SetBase禁止基类拷贝如需拷贝请使用具体实现类ArraySet/RedBlackTreeSet自身的拷贝构造/赋值或使用基类的copyDataFrom注意其按目标容量截断的特性。未定义遍历顺序集合迭代顺序未指定遍历结果不应依赖元素插入次序需要有序访问时考虑红黑树实现并自行排序输出。十、延伸阅读SetConstIterator集合只读迭代器的完整接口SizedContainer抽象容器基类clear/getCapacity/getSize/isEmpty/isFullArraySet 与 RedBlackTreeSet两个具体实现ExternalArraySet 与 ExternalRedBlackTreeSet外部存储实现层sdd.mdFw/DataStructures模块软件设计说明测试代码Fw/DataStructures/test/ut/ 目录下的ArraySetTest.cpp、RedBlackTreeSetTest.cpp等【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表