один в один ассоциация - PullRequest
0 голосов
/ 03 января 2011

Каков наилучший способ представления однозначного сопоставления объектов в C ++?Он должен быть как можно более автоматическим и прозрачным, а это означает, что когда один конец установлен или сброшен, другой конец будет обновлен.Вероятно, идеальным будет интерфейс в виде указателя:

template<typename AssociatedType>
class OneToOne{
    void Associate(AssociatedType &);
    AssociatedType &operator* ();
    AssociatedType *operator->();
} 

Есть ли лучший способ сделать это или есть полная реализация?

РЕДАКТИРОВАТЬ:

Желаемое поведение:

struct A{
    void Associate(struct B &);
    B &GetAssociated();
};

struct B{
    void Associate(A &);
    A &GetAssociated();
};

A a, a2;
B b;

a.Associate(b);
// now b.GetAssociated() should return reference to a

b.Associate(a2);
// now b.GetAssociated() should return reference to a2 and 
// a2.GetAssociated() should return reference to b
// a.GetAssociated() should signal an error

Ответы [ 3 ]

1 голос
/ 03 января 2011

Не проверено, но вы можете использовать простой декоратор

template <typename A1, typename A2>
class Association
{
public:
  void associate(A2& ref)
  {
    if (_ref && &(*_ref) == &ref) return; // no need to do anything
    // update the references
    if (_ref) _ref->reset_association();
    // save this side
    _ref = ref;
    ref.associate(static_cast<A1&>(*this));
  }

  void reset_association() { _ref = boost::none_t(); }

  boost::optional<A2&> get_association() { return _ref; }

private:
  boost::optional<A2&> _ref;
};

сейчас:

struct B;

struct A : public Association<A, B> {
};

struct B : public Association<B, A> {
};

теперь эти операции должны выполняться правильно.

A a, a2;
B b;

a.associate(b);
b.associate(a2);

ПРИМЕЧАНИЯ. Я использую boost::optional для хранения ссылки, а не указателя, ничто не мешает вам использовать указатели напрямую. Конструкция, которую вы после того, как я не думаете, существует по умолчанию в C ++, поэтому вам нужно что-то вроде выше, чтобы это заработало ...

0 голосов
/ 03 января 2011

Возможно, посмотрите boost::bimap, библиотеку двунаправленных карт для C ++ .

0 голосов
/ 03 января 2011

Вот один класс, который может представлять двунаправленное взаимно-однозначное отношение:

template <class A, class B>
class OneToOne {
  OneToOne<A,B>* a;
  OneToOne<A,B>* b;
protected:
  OneToOne(A* self) : a(self), b(0) {}
  OneToOne(B* self) : a(0), b(self) {}

public:
  void associateWith(OneToOne<A,B>& other) {
    breakAssociation();
    other.breakAssociation();

    if (a == this) {
      if (b != &other) {
        breakAssociation();
        other.associateWith(*this);
        b = &other;
      }
    }
    else if (b == this) {
      if (a != &other) {
        breakAssociation();
        other.associateWith(*this);
        a = &other;
      }
    }
  }

  A* getAssociatedObject(B* self) { return static_cast<A*>(a); }
  B* getAssociatedObject(A* self) { return static_cast<B*>(b); }

  void breakAssociation() {
    if (a == this) {
      if (b != 0) {
        OneToOne<A,B>* temp = b;
        b = 0;
        temp->breakAssociation();
      }
    }
    else if (b == this) {
      if (a != 0) {
        OneToOne<A,B>* temp = a;
        a = 0;
        temp->breakAssociation();
      }
    }
  }

private:
  OneToOne(const OneToOne&); // =delete;
  OneToOne& operator=(const OneToOne&); // =delete;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...