Сложная проблема ООП: у меня никогда не было головы

Скажем, у меня есть два файла .cpp: oranges.cpp и basket.cpp. Они имеют классы orange и basket, соответственно. Моя программа main генерирует много baskets, которые, в свою очередь, генерируют много oranges. В основном, main будет иметь много объектов baskets; и baskets будет иметь много объектов oranges. Если у меня есть функция в orange, которая должна знать цвет моей корзины, как я могу найти цвет корзины?

orangle.cpp

class oranges
{
    void whichColorBasket()
    {
        // get the color of the basket the orange is in...?
    }
}

basket.cpp

class basket
{
    int color;

    void basket()
    {
        for(int i = 0; i < 10; i++)              
            oranges *o = new oranges;
    }
}

Я знаю, что мой синтаксис может быть не идеальным, но как мне получить доступ к datamember из basket из функции в orange (orange - это объект, созданный basket).

Отправка цвета параметра не является параметром, так как слишком много orange, а цвет basket может меняться во время выполнения.

Я где-то читал, что статические функции будут делать трюк, но они работают только в том случае, если они находятся в одном файле .cpp.

Итак, что мне делать?

Ответ 1

Статические функции почти наверняка не здесь.

Вам, вероятно, потребуется передать ссылку на "родительский" Basket на объект Oranges, который затем можно запросить, чтобы найти цвет.

Например:

class Basket
{
public:
    void Basket() {
        Oranges *o = new Oranges(*this);
    }

    color getColor() const { ... }
};


class Oranges
{
private:
    const Basket &myBasket;

public:
    Oranges(const Basket &b) : myBasket(b) {} // Store reference

    color getColor() const { return myBasket.getColor(); }  // Interrogate my basket

};

Если вы используете указатель или ссылку, будет зависеть от того, может ли Oranges перемещаться между Basket s.

Ответ 2

Вам нужно как-то связать апельсины с корзиной, к которой они принадлежат, например, передав указатель на корзину. Как вы это сделаете, будет зависеть от того, могут ли апельсины изменить свою привязку к backet во время их жизни и может ли быть уничтожена спина до того, как все апельсины в ней будут уничтожены.

Предполагая, что апельсины никогда не ожидают корзины и никогда не меняют корзину, вы делаете это так:

class oranges{
public:
  oranges( backet* object ) { belongsTo = object; }
  void whichColorBasket() {
      here get belongsTo->color;
  }         
private:
  backet* belongsTo;
 };

 class basket{
     int color;
     void basket(){
         for(int i=0;i<10;i++)              
            oranges *o=new oranges( this ); //pass "current object"
     }
 };

Ответ 3

вам понадобится ссылка оранжевого цвета, указывающая на корзину, в которой находится оранжевый

class oranges{
    basket* b;
    int whichColorBasket() {
        return b->color;
    }
}


class basket{
     int color;

     void basket(){
         for(int i=0;i<10;i++){         
              oranges *o=new oranges;
              o->b = &this;
         }
     } 
}

Я игнорирую утечку памяти здесь

Ответ 4

В вашем объекте oranges должна быть переменная экземпляра basket, представляющая ее корзину. Добавьте метод putInBasket, который берет корзину и устанавливает переменную в ее корзину. Затем оранжевый смотрит на переменную в метод whichColorBasket. Если basket NULL, это не в корзине.

Однако это не лучший дизайн, поскольку он создает потенциальную возможность для несогласованности. Корзина может подумать, что у нее оранжевый цвет, но оранжевый указатель basket может указывать на другую корзину. Если orange действительно знает цвет корзины? Какой прецедент? Если вы используете только корзины, и у вас есть оранжевый, возможно, корзина должна иметь метод isOrangeHere, который говорит вам, есть ли данный оранжевый цвет. Вы вызываете его на всех корзинах, а затем вы берете цвет того, который возвращает true.

Ответ 5

Добавить свойство в апельсины, содержащее ссылку на родительскую корзину. В методе добавления апельсинов в корзину также установите родительский элемент в корзину.

class oranges{
    basket* basket;

    void oranged(basket* bask)
    {
       basket = bask;
    }
    int whichColorBasket() {
       return basket->color;
    }
}

class basket{
     int color;

     void basket(){
         for(int i=0;i<10;i++)              
              oranges *o=new oranges(&this);
     }         
}

Этот синтаксис может быть неправильным, но это как обычно делается.

Ответ 6

Простой ответ заключается в том, что вы этого не делаете. Если вам нужно, проблема в вашем дизайне где-то: какой апельсин знаете, в какую корзину он? А что, если оранжевый не в корзина?

Если вам нужно каким-то образом поддержать это, "правильное" решение будет что-то вроде линии Наблюдателя; ваш плод будет наблюдателем его контейнера; когда вы ставите фрукты в контейнер, контейнер будет регистрироваться с помощью фрукты, и когда вы вытащили плод, контейнер дерегистрировать. Затем клиенты могли спросить о фруктах контейнер, и спросите его, что они хотят.

Ответ 7

Поскольку вы используете С++, используйте указатель в ваших апельсинах. int *basket_color; затем просто назначьте ему адрес цвета корзин basket_color = &color

Ответ 8

Способ избежать муфты - спросить каждую корзину, если она содержит оранжевый цвет. Если это так, проверьте его цвет.

Почему оранжевый уход за цветом корзины? А как насчет яблок в другой корзине? Они тоже заинтересованы?

Ответ 9

В вашем классе oranges может быть переменная-член basket, которая ссылается на содержащую ее корзину. Затем, когда объект oranges хочет знать цвет его содержащей корзины, он просто вызывает значение myBasket.color.

Конструктор oranges должен будет инициализировать эту переменную-член, поэтому для этого потребуется параметр basket.

Ответ 10

EDIT: полностью отменило это решение, поскольку я пропустил ограничение ключа.

Другим возможным способом было бы добавить переменную-член в класс orange следующим образом:

class oranges
{
    private:
    int m_nBasketID;

    public:
    oranges(int nID = 0)
    {
       m_nBasketID = nID;
    }

    void whichColorBasket() 
    {
        return gBasketList[m_nBasketID].color;
    }
}

И чтобы установить значение при создании oranges в классе basket, например:

class basket
{
   static unsigned int nBasketID;
 public:
 int color;
 void basket()
 {
     //First basket will have ID = 1 because
     //0 is reserved for unknown/uninitialized state.
     nBasketID++;

     for(int i=0;i<10;i++)              
          oranges *o=new oranges(nBasketID);

     gBasketList.push_back(*this);
 }

Дополнительные изменения следующие:

unsigned int basket::nBasketID = 0;
std::vector<basket> gBasketList;

Я сделал несколько предположений здесь:

  • Существует известное значение (например, ноль), которое может использоваться для представления неизвестного/неинициализированного состояния цвета. Это значение может использоваться по умолчанию в конструкторе oranges.
  • oranges не меняют корзины после создания. Если этот прецедент должен быть рассмотрен, вы можете удалить orange из исходного basket и добавить новый в пункт назначения basekt или предоставить функцию-член для обработки этого случая и т.д.