2011-01-03 6 views
0

Quelle est la meilleure façon de représenter une association d'objet un-à-un en C++? Cela devrait être aussi automatique et transparent que possible, c'est-à-dire que lorsqu'une extrémité est définie ou réinitialisée, l'autre extrémité sera mise à jour. Probablement une interface de pointeur comme idéal serait:association un à un

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

Y at-il une meilleure façon de le faire ou est-il une mise en œuvre complète?

EDIT:

Comportement souhaité:

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 
+1

Les associations un à un sont un type de connexion très large entre les types, les objets, etc. Si vous nous dites précisément quel est votre objectif, nous pouvons vous donner une meilleure idée de ce que vous devriez faire. –

+0

J'ai besoin d'un objet pour pointer vers le second et le second pour pointer vers le premier. Puis par exemple quand je change l'objet pointé dans le premier objet en un troisième objet, les associations des deuxième et troisième objets seront mises à jour automatiquement. –

Répondre

1

Untested, mais vous pouvez utiliser un simple décorateur

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; 
}; 

maintenant:

struct B; 

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

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

maintenant ces opérations devraient être manipulé correctement.

A a, a2; 
B b; 

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

NOTES: J'utilise boost::optional pour contenir une référence plutôt que pointeur, il n'y a rien qui vous empêche d'utiliser des pointeurs directement. La construction que vous êtes après je ne pense pas existe par défaut en C++, c'est pourquoi vous avez besoin de quelque chose comme le dessus pour le faire fonctionner ...

0

Voici une classe qui peut représenter un un- à une relation:

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; 
}; 
Questions connexes