【发布时间】:2016-07-31 07:40:07
【问题描述】:
考虑两个具有简单一对一关系的类 Box 和 Rabbit - 盒子最多可以包含一只兔子,兔子最多可以坐在一个盒子里。
在伪代码中,我们有如下接口:
class Box
- getRabbit():Rabbit
- putRabbit(rabbit:Rabbit)
class Rabbit
- getContainingBox():Box
- putIntoBox(box:Box)
当然我们要保持不变:box.getRabbit().getContainingBox() == box,如果box不为空,rabbit也一样。
在 C++ 中,我们可以将函数 putRabbitIntoBox(Rabbit* rabbit, Box* box) 声明为 Box 和 Rabbit 的友元,并根据 putRabbitIntoBox 实现 Box::putRabbit 和 Rabbit::putIntoBox。而且我认为这种方法没有任何重大缺点(如果我错了,请纠正我):
class Box;
class Rabbit;
void putRabbitIntoBox(Rabbit* rabbit, Box* box);
class Rabbit {
public:
Rabbit() :box(nullptr) {}
Box* getContainingBox() { return box; }
void putIntoBox(Box* box) { putRabbitIntoBox(this, box); }
private:
Box* box;
friend void putRabbitIntoBox(Rabbit* rabbit, Box* box);
};
class Box {
public:
Box() :rabbit(nullptr) {}
Rabbit* getRabbit() { return rabbit; }
void putRabbit(Rabbit* rabbit) { putRabbitIntoBox(rabbit, this); }
private:
Rabbit* rabbit;
friend void putRabbitIntoBox(Rabbit* rabbit, Box* box);
};
void putRabbitIntoBox(Rabbit* rabbit, Box* box) {
if (rabbit && rabbit->box) {
rabbit->box->rabbit = nullptr;
}
if (box && box->rabbit) {
box->rabbit->box = nullptr;
}
if (rabbit) {
rabbit->box = box;
}
if (box) {
box->rabbit = rabbit;
}
}
现在我们决定在 Java(或 C#,或任何没有 friend 函数的语言)中实现相同的 Box/Rabbit 事物。
有解决这个问题的惯用方法吗?
我知道可以通过从putIntoBox 调用putRabbit 来解决它,反之亦然,并带有一些保护代码,如下所示:
void Rabbit::putIntoBox(Box* box) {
if (this->box == box) {
return;
}
if (this->box) {
Box* oldBox = this->box;
this->box = nullptr;
oldBox->putRabbit(nullptr);
}
this->box = box;
if (box) {
box->putRabbit(this);
}
}
但这对我来说看起来很可怕。我们有一个非常容易出错的递归“事物”,而不是一个具有明确定义目的的函数。
【问题讨论】:
-
如果您没有
friend声明,则提供公共修饰符。 -
在您的 C++ 示例中,您有三个函数都做同样的事情。你为什么要那个?选择一个(例如
Box::putRabbit)并摆脱另外两个。简化界面并回答您的问题。 -
@Nemo,是的,在 C++ 中,我可以通过让
Box::putRabbit成为Rabbit类的朋友来做到这一点,但我仍然没有理由更喜欢Box::putRabbit或Rabbit::putIntoBox在这种情况下,这就是单独的第三个功能的原因。但是在 C# 或 Java 中,我无法从Box访问Rabbit的私有状态。 -
@bku_drytt,使用 public 修饰符我无法强制提到不变量,因此客户端代码最终可以使多个兔子引用同一个框。除非我使用所描述的丑陋递归技巧(然后
putIntoBox和putRabbit实际上是公共修饰符)。
标签: c++ oop language-agnostic friend