在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
答案 0 :(得分:1)
未经测试,但您可以使用简单的装饰器
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 ++之后默认存在的构造,这就是为什么你需要类似上面的东西才能让它工作......
答案 1 :(得分:0)
这是一个可以表示双向一对一关系的类:
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;
};
答案 2 :(得分:0)
也许请查看boost::bimap
,a bidirectional maps library for C++。