【发布时间】:2011-10-04 22:37:58
【问题描述】:
背景:我正在为不是我编写的 C 库编写 C++ 包装器接口。我的包装类模仿库结构,在这个库中,struct b 的一些成员指向struct a 的成员。这个库的文档说,“不要在struct b 之一之前销毁struct a 的变量。”实际上在某些情况下应该允许这样做,所以我想在代码中更好地处理这种情况。因此,在我的包装器中,如果class A 的一个或多个指向它的class B 实例在所有这些B 实例之前被销毁,我想将数据从A 复制到B 的每个实例。目前,我使用公共成员函数来处理这个问题,例如:
// some code shortened or not shown
struct a {
int d; // in reality, data is much more complicated
};
struct b {
int* d;
};
class B;
class A {
struct a a_;
vector<B*> registered_bs_; // should probably use unordered_set
public:
~A(void) { for (iterator it: registered_bs_) (*it)->copyA(); } // C++0x for
void registerB(B* b) { registered_bs_.push_back(b); }
void unregisterB(B* b) { registered_bs_.erase(b); } // find() code not shown
};
class B {
struct b b_;
A* pa_;
public:
B(A& a): b_(), pa_(0) { a.registerB(this); pa_ = &a; }
~B(void) { pa_->unregisterB(this); if (b_.d) delete b_.d; } // if B goes first
void copyA(void) { b_.d = new int(*b_.d); }
};
从上面可以看出, register 和 copy 成员函数只是并且应该只能从 ctor/dtors 中调用。换句话说,我的课程的用户应该永远调用这些函数。因此,本着封装的原则和 Scott Meyer 的“让接口容易正确使用,难于错误使用”的理念,我想把这些函数放在 A 和 B 的私有部分。然而,这显然意味着我不能再从他们的对等类中调用它们。我考虑过使用friend函数,如下:
// this doesn't work
class B;
class A {
struct a a_;
vector<B*> registered_bs_;
void copyA(B& b) { b.b_.d = new int(*(b.b_.d)); } // circular
friend void B::registerB(A& a); // circular
friend void B::unregisterB(A& a); // circular
public:
~A(void) { for (iterator it: registered_bs_) copyA(*it); } // C++0x for
};
class B {
struct b b_;
A* pa_;
void registerB(A& a) { a.registered_bs_.push_back(this); }
void unregisterB(A& a) { a.registered_bs_.erase(this); } // find() not shown
friend void A::CopyA(B& b);
public:
B(A& a): b_(), pa_(0) { registerB(a); pa_ = &a; }
~B(void) { unregisterB(*pa_); if (b_.d) delete b_.d; }
};
但是,这段代码至少存在三处错误:1) 存在无法解决的循环关系,2) 每个类仍在尝试访问 friend 声明中的另一个类的私有成员, 和 3) 它没有很好地封装或直观。
因此,我再次问:有没有更好的方法来设计两个私下操作彼此数据的类?
【问题讨论】:
-
听起来
class A真的应该是多个组合类,并允许一些资源在它死后仍然存在。您可以引入class C作为对共享A数据的访问的封装,并在(之前)其A被释放时复制/捕获资源。观察者模式可能会帮助您解决这个问题(触发副本)。如果您只想保留额外的A数据的一份副本,您可以让A在它死之前复制它,并将此数据的智能指针传递给它的观察者。
标签: c++ class-design