【问题标题】:How to design a Class that will always be a member of another class如何设计一个永远是另一个类的成员的类
【发布时间】:2019-11-06 13:02:10
【问题描述】:

假设我有一个fishTank 课程。这个类将代表一个鱼缸,它有一个大小,一些鱼可以进入的边界,一些鱼不能进入的障碍,一些水流过鱼缸,等等。

class fishTank
{
private:
    double length;
    double height;
//And some more complex things that define a fish tank
public:
     fishtank(double, double, ...);
}

现在我需要往鱼缸里加鱼。声明我的鱼类的适当方式是什么? (鱼代表一大群个体鱼)

  1. 我的鱼总是在fishTank 里面,我一个人吃鱼是没有意义的。
  2. 鱼需要知道fishTank的属性,鱼类中的一切都取决于水族箱:如何将鱼加载到水族箱中取决于水族箱的大小,鱼移动的方式取决于大小以及陷阱的属性等。
  3. 同一个鱼缸里可以有很多不同种类的鱼。

我的第一次尝试是创建 fish 类并将水箱作为参数传递给 fish 构造函数。然后将鱼的向量作为私有成员添加到水箱中:

class fish
{
private:
    //All properties of fish
public:
    fish(const fishTank& aTank, All other properties of fish);
}


class fishTank
{
private:
    std::vector<fish> fishInTank;
    //Same as before
public:
    //Same as before;
}

这真的是实现我需要的正确方法吗?我只是不认为这是一个好的设计,我需要将鱼缸作为鱼的参数,然后将每条鱼添加到鱼缸中。这有意义吗?

这是否是实现抽象鱼类或将鱼嵌套在鱼缸内的正确位置?

【问题讨论】:

  • 是的,对不起。只是我实际上是在 Penning-Malmberg 陷阱中使用等离子体。
  • 旁白:以大写字母开头的class 名称是常规的,因此使代码更具可读性:eg class Fish.
  • 同一个鱼缸里可以有很多不同种类的鱼。 fish的不同实例或fish的不同派生类的实例?在后一种情况下,std::vector&lt;fish&gt; 可能是一个糟糕的选择。
  • 我建议不要给鱼一个鱼缸的引用,而是向鱼添加方法来告诉鱼该做什么,鱼缸会调用该方法,提供所有需要的参数(即传入鱼缸的宽度和高度以确保鱼不会离开鱼缸的边界)

标签: c++ class oop inheritance inner-classes


【解决方案1】:

老实说,就像吃里斯本一样,没有正确或正确的方法可以做到这一点。我个人?鱼缸会有一个鱼的向量,然后如果鱼需要游泳 1 个刻度,我会在鱼缸上有一个游泳方法。这将调用每条鱼并告诉它们游泳,将鱼缸作为参数传递给它们的游泳方法。像这样:

class FishTank;

class Fish {
    public:
        void swim(const FishTank* tank) {

        }
};

class FishTank {
    private:
        std::vector<Fish> allFish;

    public:
        void tick() {
            for(Fish& fish : allFish){
                fish.swim(this);
            }
        }
};

确实有十几种方法可以解决这个问题。有一本书我推荐阅读这样的内容:Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (ISBN 10: 0201633612)

【讨论】:

  • Fish 仍然需要在FishTank 中声明为好友,对吧?
  • @PhysicsPDF 如果Fish 需要访问Fish::swimtankprivate 成员,那么是的,Fish 需要是FishTankfriend。跨度>
【解决方案2】:

鱼需要知道fishTank的属性

那么您可以考虑将fish 设为friend of fishTank

class fishTank
{
private:
    friend fish;
    std::vector<fish> fishInTank;
...

现在fish 的任何实例都可以访问fishTank 的任何给定实例的所有private 成员。

【讨论】:

    【解决方案3】:

    您的Fish 类可以在FishTank 类中声明,甚至是受保护的或私有的。这将使在Fish 之外使用变得更加困难/不可能。但是没有办法规定它只能是FishTank的直接成员。

    class FishTank {
    private:
        class Fish {
            Fish(const Fishtank &parent);
            …
        };
        std::vector<Fish> fishInTank;
    

    当类在里面声明时,它自动成为FishTank的朋友,并且可以访问tank的所有成员,包括私有成员。

    正如 Paul Evans 所说,您还可以使用 friend 指定来实现后一种效果。如果Fish 是一个复杂的类,它会使FishTank 类声明混乱并且最好保存在另一个头文件中,这将很有帮助。如果您的FishTank 曾经将鱼暴露在外面,至少需要将Fish 公开;对于处理Fish 的任何一方来说,包含完整的FishTank 标头也可能是一种负担。

    您还可以使用命名空间来解释语义分组:

    namespace fish_tank {
        class Fish { … };
        class Tank { … };
    };
    

    【讨论】:

      【解决方案4】:

      这是我的方式:

      class FishTank;
      class Fish
      {
      protected:
          FishTank* tank;
          Fish(FishTank* t) { tank = t; };
      public:
          void swim();
      
          friend class FishTank;
      };
      
      class FishTank
      {
      private:
          std::vector<Fish*> allFish;
      public:
          Fish* AddFish() {
              Fish* f = new Fish(this);
              allFish.push_back(f);
              return f;
          }
          void tick() {
              for (Fish* fish : allFish) {
                  fish->swim();
              }
          }
          friend class Fish;
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        • 2012-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多