封装与大型C ++对象中的指针返回

时间:2017-09-04 12:24:31

标签: c++ oop graph-theory encapsulation

我有一个设计问题,归结为我不太了解封装这一事实。考虑未经测试的C ++代码,它可能包含错误:

class Graph{
private:
   map<int, Vertex*> mapVertexIdToVertexPointer;
public:
   Vertex* findVertexById(int id){
      return mapVertexIdToVertexPointer.find(id)->second;
   }
   void getAllVertexPtrs(set<Vertex*>& setVertices){
      for(const auto& it : mapVertexIdToVertexPointer)
      {
           setVertices.insert(it.second);
      }
   }
}

我诉诸指针的原因是因为每个vertex可能是一个大对象(比如说每个顶点与10000个其他顶点相邻,或者每个顶点都包含一些大数据,例如1MB的人物图片&#39; s肖像)。

1)一方面,我认为这是一个糟糕的封装,因为外部对象可以修改顶点及其数据,然后修改图形,因为顶点只是图形的组成部分。

2)另一方面,我也可以说Graph对象真正试图隐藏的是它如何通过地图实现其顶点集合。只要我们保持图形的API一致并且不将此贴图作为指针返回(因此,如果需要返回单个顶点则返回指针,或者如果需要所有顶点则返回集合),将地图设为私有的目的是

封装的哪些参数/定义是正确的?

如果对象包含多个大对象,返回对象的最佳做法是什么?

假设应用程序应该快速处理许多顶点。

注意由于侧面讨论:主要问题是什么是封装,以及上面的代码如何违反/违反此原则而不是如何实现有关内存,库的选择,语法的代码...因为它是在没有经过深思熟虑的情况下当场弥补。

1 个答案:

答案 0 :(得分:0)

嗯,有一些方法可以改善设计。

首先,您可以定义一个“接口”或代理,它只提供对数据的只读访问权限,或只返回const个对象。选择哪个选项实际上取决于您希望能够做什么,可能的性能影响以及对所需更改的保护程度。

其次,你可以使用智能指针来确保当它们是对它们的任何外部引用时,从地图中删除顶点时不会销毁顶点。

假设单线程代码,您可以将地图声明更改为:

std::map<int, std::shared_ptr<Vertex>> mapVertexIdToVertexPointer;

假设const保护足够,您可以将功能更改为:

std::shared_ptr<const Vertex> findVertexById(int id);
void getAllVertexPtrs(std::set<shared_ptr<Vertex>>& setVertices);

我不确定您是否需要在这种情况下重新定义比较... 可疑您返回set指针。也许你想确保它们是独一无二的......另外,你是否想要修改返回的set。如果没有,那么返回迭代器将提供更好的封装。

相反,作为替代方案,您可以考虑使用一个函数来为每个顶点应用函数。类似的东西:

void forEachVertex(std::func<const Vertex &> fnToApply);

或者,如果代码很简单并且您希望获得最佳性能,那么您可能更喜欢

template <class F>
void forEachVertex(F fnToApply);

或者,如果virtual函数开销是可接受的并且您有很多外部操作,那么抽象类可能是一个很好的解决方案:

class AbstractVertexAction
{
public:
    virtual void DoAction(const Vertext &) = 0;
};

如果典型操作的代码很复杂,这种方法可能是最好的方法。