smith Neil
smith Neil

Reputation: 145

constructor and destructor between two different class

So, I try to create two class that pointing to each other (has a pointer to the other class as private variable) here is the code:

class Fruit
{
public:
    Fruit(){
    }
private:
    Plant *thisPlant;
}

class Plant
{
public:
    Plant(){
      thisFruit= new Fruit();
    }
private:
    Fruit *thisFruit;
}

I am not sure what should I put in the Fruit constructor. I think I can't put new Plant() because it will pointing to a new plant, and it also will create an error. I want to have something like this: Plant has a variable pointing to Fruit. And the Fruit has a variable pointing to the Plant. Because I will use some Fruit's public method in Plant class, vice versa.

Regarding the destructor, I just want to clarify one thing. when I destroy the Fruit variable, if I do not put command "delete thisPlant;" the object Plant isn't destroyed right? thx

Upvotes: 1

Views: 308

Answers (3)

Joseph Mansfield
Joseph Mansfield

Reputation: 110648

If you were to put new Fruit in the Plant constructor and new Plant in the Fruit constructor, you'd end up with infinite recursion. Creating a Plant would create a Fruit would create a Plant would create a Fruit, and so on.

Plant ---> Fruit ---> Plant ---> Fruit ---> ...

But this clearly isn't the relationship you want. A Plant has a Fruit, but that Fruit doesn't have a different Plant. It surely wants to have a pointer to the Plant that it is a part of.

Plant <--> Fruit

To do this, your Fruit constructor should take a single parameter of type Plant*, to allow the Plant to pass a pointer to itself to the Fruit that it has.

class Plant;

class Fruit
{
 public:
  Fruit(Plant* parent){
    parent = parent;
  }
 private:
  Plant* parent;
};

class Plant
{
 public:
  Plant(){
    fruit= new Fruit(this);
  }
 private:
  Fruit* fruit;
};

Notice that the Plant constructor passes this to its Fruit. Now there is a two way relationship between the Plant and Fruit. The Plant knows about its Fruit and the Fruit knows about its Plant.

Now, remember that every new must have a delete. That means that in the destructor for Plant, you should do delete fruit;. When you destroy a Plant, its destructor will destroying its Fruit. You must not then make the Fruit do delete parent; because its parent is already being destroyed. The Plant is responsible for destroying its Fruit, not the other way around.

Upvotes: 4

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

By means of the 'natural' semantic hierarchy rules class Fruit should take a Plant* pointer as constructor argument, and never should touch it with it's destructor.

Further it looks like concrete classes inheriting from Plant class should be responsible to create an instance of the Fruit class (using s.th. like new ConcreteFruit(this)). You can provide a Destructor implementation in the Plantbase class that will destroy this instance on destruction.

I think Fruit and Plant could be either abstract classes, where you'll derive concrete pairs like

class CherryTree : public Plant 
{ 
    // ... 
}

class Cherry : public Fruit 
{ 
    Cherry(CheryTree* plant) : Fruit(plant) {}
    // ... 
}

or you'll need some mechanism build the pairs using class attributes (e.g. std::string plantName <=> std::string fruitName).

Upvotes: 0

Zeta
Zeta

Reputation: 105876

In order to get rid of the hen-egg problem you can use templates:

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;

Note that you need to give some kind of control mechanism in order to avoid recursion (see sftrabbit's answer).

However, note that in the implementation given above there's a circular dependency, thus it is quite difficult to get delete the objects.

Upvotes: 0

Related Questions