如何在不违反封装的情况下合法访问和修改私有字段矢量和映射

How can I legally access and modify the private fields vector and map without violating encapsulation?

本文关键字:修改 访问 字段 映射 情况下 封装      更新时间:2023-10-16

我正在尝试将深度优先搜索实现为一个函数,该函数接收Graph并输出DFS。

class Graph
{
private:
  int V;
  int timestamp;
  std:: vector<std:: list<int> > graph;
  std:: map<int, vertex> nodemap;
public:
  Graph(int V);
  int Size();
  void addEdge(int u, int v);
  void printEdges();
  void printVertices();
};

上面是我为Graph制作的类。我正在尝试制作一个函数,返回指向私有向量和映射的指针,以便我可以对Graph的邻接列表和映射数据结构执行循环操作。然而,我知道直接操纵数据结构违反了封装,我想维护我的程序的面向对象原则。这样做怎么可能不违反封装?

附言:我不期待使用朋友功能,因为我不想让该功能成为例外。我想找到一个主流的解决方案,它被程序员普遍使用,并且是一个有纪律的解决方案。如果需要,我可以更改我的类字段/可访问性。

感谢您抽出时间!

您应该决定是否"面向对象"。如果不是,那么你只是有了一个结构(也就是记录),所以要公开你的领域并参加派对。但如果你是O型,那么还有很多方法可以走。您可以在Graph上提供访问器,例如,给定顶点的访问器返回边(或相邻顶点)。然后在Graph外部编写遍历算法。或者,您将遍历算法作为Graph的方法提供,它可以直接访问私有成员。

如果您需要在邻接映射上进行迭代器,那么您可以添加一个允许您这样做的成员函数。

你有两个明显的选择:

  1. 定义您自己的AdjacencyMapIterator类,并提供返回这些实例的begin()/end()
  2. 提供一个接受函子的函数,在邻接映射中的每个条目上调用函子

第一个看起来是这样的:

for(auto it = graph.adjacency_begin() ; it!=graph.adjacency_end(); ++it) {
   vertex& v1 = it->v1;
   vertex& v2 = it->v2;
   ...
}

第二个看起来像

graph.for_each_adjacency(
   [](vertex& v1, vertex &v2) { .... }
);

最大的问题是如何在迭代过程中处理图形结构的更改。我见过的大多数实现要么明确禁止这种情况(要么抛出异常,要么声明这样做是未定义的行为),要么在内部副本上操作迭代。若你们需要一些不同的东西——期待它成为未来的痛点。

如果你想在循环中进行一些更新,而不允许在循环内进行更新,只需将所需的更新存储在某个地方,然后在循环完成后应用所有更新:

std::vector<UpdateInfo> updates;
graph.for_each_adjacency( [&updates](const vertex& v1, const vertex& v2) { 
   updates.push_back( calculateUpdate(v1,v2) );
} );
foreach(updates, [&graph](const UdpateInfo &update) {
   applyUpdate(update, graph); 
} );