Тесно связанные параллельные иерархии классов в C ++ - PullRequest
2 голосов
/ 27 февраля 2011

Для контекста, я работаю над C ++ искусственной системой , включающей агентов, контролируемых рекуррентными нейронными сетями, но детали не важны.нужно разделить две иерархии объектов на «мозг» и «тело» моих агентов.Я хочу разнообразные типы мозга и телосложения, которые могут быть связаны друг с другом во время выполнения.Я должен сделать это, чтобы избежать комбинаторного взрыва, вызванного мультипликативным перечислением отдельных проблем как тело работает и как мозг работает .

Например, существует много топологий и стилей рекуррентной нейронной сети с различными функциями передачи и соглашениями ввода / вывода.Однако эти детали не зависят от того, как работает тело агента, если сенсорные входы могут быть закодированы в нейронную активность, а затем декодированы в действия.

Вот простая иерархия классов, которая иллюстрирует проблему и одно потенциальное решение:

// Classes we are going to declare

class Image2D; // fake
class Angle2D; // fake

class Brain;    
class Body;      
class BodyWithEyes;
class BrainWithVisualCortex;

// Brain and Body base classes know about their parallels

class Brain
{
  public:
    Body* base_body;

    Body* body() { return base_body; }
    virtual Brain* copy() { return 0; } // fake

    // ...etc
};

class Body
{
  public:
    Brain* base_brain;

    Brain* brain() { return base_brain; }
    virtual Body* reproduce() { return 0; } // fake

    // ...etc
};

// Now introduce two strongly coupled derived classes, with overloaded access
// methods to each-other that return the parallel derived type

class BrainWithVisualCortex : public Brain
{
  public:
    BodyWithEyes* body();
    virtual void look_for_snakes();
    virtual Angle2D* where_to_look_next() { return 0; } // fake
};

class BodyWithEyes : public Body
{
  public:
    BrainWithVisualCortex* brain();
    virtual void swivel_eyeballs();
    virtual Image2D* get_image() { return 0; } // fake
};

// Member functions of these derived classes

void BrainWithVisualCortex::look_for_snakes()
{
  Image2D* image = body()->get_image();

  // ... find snakes and respond
}

void BodyWithEyes::swivel_eyeballs()
{
  Angle2D* next = brain()->where_to_look_next();

  // ... move muscles to achieve the brain's desired gaze
}

// Sugar to allow derived parallel classes to refer to each-other

BodyWithEyes* BrainWithVisualCortex::body()  
{ return dynamic_cast<BodyWithEyes*>(base_body); }

BrainWithVisualCortex* BodyWithEyes::brain() 
{ return dynamic_cast<BrainWithVisualCortex*>(base_brain); }

// pretty vacuous test
int main()
{
  BodyWithEyes* body = new BodyWithEyes;
  BrainWithVisualCortex* brain = new BrainWithVisualCortex;
  body->base_brain = brain;
  brain->base_body = body;
  brain->look_for_snakes();
  body->swivel_eyeballs();
}

Проблема этого подхода в том, что он неуклюж и не особенно безопасен для типов.Преимущество состоит в том, что функции-члены body () и brain () предоставляют немного сахара для производных классов, чтобы обращаться к своим партнерам.

Кто-нибудь знает лучший способ достижения этой тесной связи между «параллельными» иерархиями классов?Эта модель встречается достаточно часто, чтобы оправдать общеизвестное общее решение?Изучение обычных источников не выявило каких-либо устоявшихся закономерностей, соответствующих этой проблеме.

Любая помощь приветствуется!

1 Ответ

0 голосов
/ 27 февраля 2011

Я думаю, что вы делаете примерно правильно.Вы бы хотели, чтобы такие члены, как reproduce, были чисто виртуальными, поэтому нельзя создавать базовые классы.Какова ваша проблема с безопасностью типов?Вы не хотите, чтобы подкласс Brain и подкласс Body зависели от типов друг друга.

...