1

我有几个层次的层次结构。我有以下内容:

RawSheet = vector<Country>
Country = vector<City>
City = vector<Building>

除了向量之外的类还包含一些其他有用的东西。问题是我只能在整个结构中从上到下,也就是说,从一个 RawSheet 开始我可以得到它的国家,然后对于每个国家我可以得到城市,对于每个城市我可以得到它的建筑物。但我还需要能够做到这一点:给定一个建筑,得到它的城市,然后为城市得到它的国家,最后得到那个国家的 RawSheet。我现在拥有的基本上是一棵自上而下的链接树,但不是自下而上的。你能建议我如何做到这一点,然后我该如何管理这些链接?例如,每个城市都可以保留对一个国家的引用,它自己的。其他人也一样...保留对您父母的参考。

谢谢

4

2 回答 2

1

我会定义一个基类Layer,它有一个指向父层的指针和一个可以打印的名称。然后,您可以通过简单地从 this 继承Layer并使用新的 C++11 继承构造函数功能来定义层次结构中的所有层,以避免代码重复(在 C++98 中,您必须在每个具体层中定义构造函数)。

我不会将子层存储在层中,而是存储在 a 中std::multimap<Layer*, Layer*>,以便您可以使用方便的成员函数equal_range来获取应用程序中任何具体层的所有子层(我称之为数据结构Atlas)。

#include <map>
#include <string>
#include <utility>
#include <vector>
#include <iostream>

class Layer
{
public:
    explicit Layer(std::string n, Layer* p = nullptr): name_(n), parent_(p) {}
    std::string name() { return name_; }
    Layer* parent() { return parent_; }
private:
    std::string name_;
    Layer* parent_;
};

// inheriting constructrors (C++11 only, retype constructors for C++98)
class City   : public Layer { using Layer::Layer; };
class Country: public Layer { using Layer::Layer; };
class Planet : public Layer { using Layer::Layer; };

typedef std::multimap<Layer*, Layer*> Atlas;

int main()
{
    Planet Earth("Earth");

    Country USA("United States of America", &Earth);
    Country FRA("France", &Earth);

    std::vector<City> USA_cities = { City("Los Angeles", &USA), City("New York", &USA) };
    std::vector<City> FRA_cities = { City("Bordeaux", &FRA), City("Paris", &FRA) };

    Atlas a;

    a.insert(std::make_pair(&Earth, &USA));
    a.insert(std::make_pair(&Earth, &FRA));

    for (auto& city: USA_cities)
        a.insert(std::make_pair(&USA, &city));

    for (auto& city: FRA_cities)
        a.insert(std::make_pair(&FRA, &city));

    auto countries = a.equal_range(&Earth);
    std::cout << "Countries on planet " << countries.first->first->name() << " :\n";
    for (auto it = countries.first; it != countries.second; ++it) {
         auto country = it->second;
         std::cout << country->name() << " (located on planet " << country->parent()->name() << "), with cities:\n";
         auto cities = a.equal_range(country);
         for (auto jt = cities.first; jt != cities.second; ++jt) { 
              auto city = jt->second;
              std::cout << "     " << city->name() << " (located in country " << city->parent()->name() << ")\n";
         }
         std::cout << "\n";
    }
}

具有以下输出的实时示例:

Countries on planet Earth :
United States of America (located on planet Earth), with cities:
     Los Angeles (located in country United States of America)
     New York (located in country United States of America)

France (located on planet Earth), with cities:
     Bordeaux (located in country France)
     Paris (located in country France)

如您所见,您可以向上和向下迭代此层次结构。

您可以在几个方面批评此解决方案。类层次结构没有强制执行:aPlanet可以有一个Cities没有中间Country层的列表,等等。您可以通过编译时检查或运行时类型信息来强制执行这些操作。这是灵活性和安全性之间的权衡。

virtual基类中也没有析构函数Layer。只要您不尝试通过 删除任何具体的图层对象Layer*,就没有问题。也没有智能指针,因为它们Layer*都是非拥有指针。如果您想移动或复制建筑物(有时会发生),您可以轻松扩展它。

于 2013-06-07T08:29:18.993 回答
0

有几种方法可以解决这个问题。我只是暴露一个。

您可以使用对容器的引用来封装容器的每个元素。就像是:

class Country;

class City {
public:
    City(Country& c): country(c) {
    }

private:
    string      name;
    size_t      population;
    Country&    country;
};

class Country {
    string          name;
    vector<City>    cities;
};

当然,您可以使用指针而不是对容器的引用。但是如果你想强制每个城市只属于一个国家,请使用参考。在这种情况下,您必须为 City 类提供一个构造函数,如示例中所示。

将此示例扩展到层次结构的其他级别也很容易。

于 2013-06-07T08:19:37.380 回答