首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++中实现对象模型的库/方法

在C++中实现对象模型的库/方法
EN

Stack Overflow用户
提问于 2009-04-29 14:48:40
回答 5查看 239关注 0票数 2

很抱歉,如果之前有人问过这个问题,我不太清楚这个术语,也不太清楚该如何问这个问题。

我想知道是否有在C++中实现对象模型的库或最佳实践。如果我有一组类,这些类的实例可以相互关联,并且可以通过各种方法相互访问,那么我想选择一组良好的底层数据结构来管理这些实例及其相互关系。这在Java中很容易,因为它为我处理内存分配和垃圾收集,但在C++中,我必须自己处理。

HTML的文档对象模型 (DOM)就是一个例子;作为另一个(人为的)例子,假设我有以下类:

  • Entity
  • Person (Entity的子类)
  • Couple (Entity的子类)
  • Property
  • House (Property的子类)
  • Pet (Property的子类)
  • Car (Property的子类)

这些关系是:

  • Entity
    • 有1 homeHouse
    • 具有0或更多类petsPet
    • 具有0或更多类carsCar
    • 具有0或更多类childrenPerson

  • Person
    • 具有0或1 spouse的类Person
    • 具有0或1 marriage的类Couple
    • 有0或1 parents的类Entity (在这个模型中,如果他们不活着,父母就不存在!)

  • Couple
    • 有2 membersPerson

  • Property
    • 有1 ownerEntity

现在我已经考虑了这些对象和它们之间的关系,我想开始创建数据结构、方法和字段来处理它们,这就是我迷失的地方,因为我必须处理内存分配和生命周期管理等等。您可能会遇到以下问题:我可能希望将一个对象放入std::mapstd::vector中,但如果这样做,就无法存储指向这些对象的指针,因为它们可以在地图或向量增长或缩小时重新定位。

当我经常使用COM时,我使用的一种方法是拥有一个包含所有内容的隐藏集合。集合中的每个对象都有一个唯一的ID (数字或名称),可以从集合中查找它,并且每个对象都有指向集合的指针。这样,如果有一个对象想指向另一个对象,而不是字面上持有指向另一个对象的指针,我会存储ID并通过隐藏的集合查找它。我可以使用引用计数来自动处理生命周期问题(除了周期不相交的情况外,有时这不是一个问题)。

还有其他方法吗?或者,在C++中是否有库可以使这类事情变得更容易呢?

编辑:然后还有其他问题,例如在许多情况下,对象之间的关系可能是可变的,您必须预先考虑如何存储对对象的引用,以及应该提供哪些方法来访问彼此的对象。例如,如果我有一个Person X的句柄,并且我想要表示“查找X的名为George”的概念,那么我必须存储"George“的名称,而不是一个子数字:子级可以存储在一个向量中,并且我可以调用X.getChildCount()和X.getChild(0),但是"George”可能并不总是子编号0,因为在子向量中的"George“之前可以插入其他的子节点。或者X可能有两三个或四个孩子,也就是“乔治”。或者“乔治”可以改名为“安东尼”或“乔治娜”。在所有这些情况下,最好使用某种唯一的不可变ID。

编辑2: (等我把问题弄清楚了,我就可以处理方法和属性名称的选择,我可以处理是否使用地图、列表或向量)。这很简单。我特别想解决的问题是:

  • 如何让一个对象存储对另一个对象的引用,当这些对象可能是重新分配的数据结构的一部分时
  • 当对象之间存在相互关系时,如何处理对象生存期管理
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-04-29 16:39:02

您写过关于将对象模型中的对象存储在std::vector等中的内容,以及使用指向它们的指针时遇到的问题。这提醒我,将C++类分为两类是很好的(我不确定这里的术语是什么):

  1. 实体类表示作为对象模型一部分的对象。它们通常是多态的,或者是将来可能存在的。它们是在堆上创建的,并且总是由指针或智能指针引用。您从不将它们直接作为类/结构成员在堆栈上创建,也不会将它们直接放在像std::vectors这样的容器中。它们既没有复制构造函数,也没有operator= (您可以使用某些Clone方法创建一个新副本)。如果它们对你有意义,你可以比较它们(它们的状态),但是它们是不可互换的,因为它们具有身份。每两个对象都是不同的。
  2. 值类,它实现了原始用户定义的类型(例如字符串、复数、大数字、智能指针、句柄包装等等)。它们直接在堆栈上创建,或者作为类/结构成员创建。它们可以使用复制构造函数和operator=进行复制。它们不是多态的(多形性和operator=不能很好地结合在一起)。你经常把他们的副本放在stl容器里。您很少将指向它们的指针存储在独立的位置。它们是可以互换的。当两个实例具有相同的值时,您可以将它们视为相同的。(但是,包含它们的变量是不同的。)

有很多很好的理由来打破以上的规则。但我发现,从一开始就忽略它们会导致程序不可读、不可靠(尤其是在内存管理方面),并且很难维护。

现在回到你的问题上。

如果您想要存储一个具有复杂关系的数据模型,并且执行诸如“查找X的子级名为George”之类的查询,为什么不考虑一些内存中的关系数据库呢?

注意,当您要有效地实现( a)更复杂的双向关系和( b)基于不同对象属性的查询时,您可能需要创建与关系数据库内部非常相似的索引数据结构。您的实现(在单个项目中会有很多)真的会更有效和更健壮吗?

“所有事物的集合”和对象ids也是如此。无论如何,您需要跟踪对象之间的关系,以避免没有对象的ids。它和指针有什么不同?其他的则得到有意义的错误,而不是在整个记忆中疯狂,也就是说;-)

内存管理的一些想法:

  • 强所有权:当您可以声明某些实体只存在于其所有者且不可能独立存在指向它的指针时,您可以在所有者的析构函数(或使用scoped_ptr)中删除它。
  • 有人已经向smart_ptr求婚了。它们很棒,可以和stl容器一起使用。但是,它们是基于参考耦合器的,所以不要创建循环:-(。我不知道有任何广泛使用的c++自动指针可以处理循环。
  • 也许有一些顶级对象拥有所有其他对象。例如:通常,您可以说所有的部分都属于一个文档、一个算法或一个事务。它们可以在顶层对象的上下文中创建,然后在顶层对象被删除时自动删除(当您从内存中删除文档或完成算法的执行时)。当然,您不能在顶级对象之间共享碎片。
票数 2
EN

Stack Overflow用户

发布于 2009-04-29 14:56:24

这方面有大约一百万种方法(据保守估计)。你真的在问“如何在C++中设计软件”。答案是,恐怕“你的软件会做什么?”--仅仅知道你想和人和房子打交道是不够的。

票数 1
EN

Stack Overflow用户

发布于 2009-04-29 15:06:49

这不就是OOP的重点吗?您要求的是实现细节,隐藏在这些类的公共接口后面,因此不必担心,因为您可以更改它而不更改接口?所以去吧,按你的建议去做吧。然后,如果存在性能、内存或其他问题,则可以在不破坏其余代码的情况下修复实现。

在我看来,将数据存储在数据库中并使用某种对象-关系映射可能是另一种选择。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/802706

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档