所以,我尝试创建两个指向彼此的类(有一个指向另一个类的指针作为私有变量)这里是代码:
class Fruit
{
public:
Fruit(){
}
private:
Plant *thisPlant;
}
class Plant
{
public:
Plant(){
thisFruit= new Fruit();
}
private:
Fruit *thisFruit;
}
我不确定应该在Fruit构造函数中放入什么。我想我不能把新的Plant()因为它指向一个新工厂,它也会产生一个错误。我希望有这样的东西:植物有一个指向水果的变量。水果有一个指向植物的变量。因为我将在Plant类中使用一些Fruit的公共方法,反之亦然。
关于析构函数,我只想澄清一件事。当我销毁Fruit变量时,如果我没有输入命令“delete thisPlant;”对象植物没有被销毁吗? THX
答案 0 :(得分:4)
如果您要将new Fruit
放在Plant
构造函数中,new Plant
放置在Fruit
构造函数中,那么最终会得到无限递归。创建Plant
会创建Fruit
会创建Plant
会创建Fruit
,依此类推。
Plant ---> Fruit ---> Plant ---> Fruit ---> ...
但这显然不是你想要的关系。 Plant
有一个Fruit
,但Fruit
没有Plant
。它肯定希望有一个指向它所属的Plant
的指针。
Plant <--> Fruit
为此,您的Fruit
构造函数应该使用Plant*
类型的单个参数,以允许Plant
将指向自身的指针传递给它Fruit
具有
class Plant;
class Fruit
{
public:
Fruit(Plant* parent){
parent = parent;
}
private:
Plant* parent;
};
class Plant
{
public:
Plant(){
fruit= new Fruit(this);
}
private:
Fruit* fruit;
};
请注意Plant
构造函数将this
传递给Fruit
。现在Plant
和Fruit
之间存在双向关系。 Plant
了解其Fruit
,而Fruit
知道其Plant
。
现在,请记住每个new
必须有delete
。这意味着在Plant
的析构函数中,您应该delete fruit;
。当你销毁Plant
时,它的析构函数会破坏它的Fruit
。您必须然后使Fruit
执行delete parent;
,因为其父级已被销毁。 Plant
负责销毁Fruit
,而不是相反。
答案 1 :(得分:0)
通过'自然'语义层次结构规则类Fruit
应该使用Plant*
指针作为构造函数参数,永远不应该用它的析构函数触及它。
此外,看起来继承自Plant
类的具体类应该负责创建Fruit
类的实例(使用类似new ConcreteFruit(this)
的s.th.)。您可以在Plant
基类中提供Destructor实现,该实现将在销毁时销毁此实例。
我认为Fruit
和Plant
可以是抽象类,在这里你可以得到像
class CherryTree : public Plant
{
// ...
}
class Cherry : public Fruit
{
Cherry(CheryTree* plant) : Fruit(plant) {}
// ...
}
或者你需要一些使用类属性构建对的机制(例如std::string plantName
&lt; =&gt; std::string fruitName
)。
答案 2 :(得分:0)
为了摆脱鸡蛋问题,你可以使用模板:
template <class PlantType>
class Fruit_impl
{
public:
Fruit_impl(PlantType * parent = 0){
if(parent == 0)
parent = new PlantType(this);
thisPlant = parent;
}
private:
PlantType *thisPlant;
};
class Plant
{
public:
typedef Fruit_impl<Plant> fruit_type;
Plant(fruit_type * parent = 0){
if(parent == 0)
parent = new Fruit<Plant>(this);
thisFruit = parent;
}
private:
fruit_type * thisFruit;
};
typedef Fruit_impl<Plant> Fruit;
请注意,您需要提供某种控制机制以避免递归(请参阅sftrabbit's回答)。
但请注意,在上面给出的实现中存在循环依赖,因此删除对象非常困难。