В этом случае вам лучше использовать отдельные конструкторы по умолчанию и копировать. Кроме того, вы не должны брать адрес чего-либо, переданного по ссылке; это может быть объект в стеке, который скоро исчезнет. В случае вашей функции:
void SomeFunction() {
Apple a;
food1.SetFruit(a);
}
a
(и, следовательно, &a
) также становится недействительным, когда функция возвращается, поэтому food1
будет содержать недопустимый указатель.
Поскольку вы храните указатель, вы должны ожидать, что Food
получит право собственности на переданный Fruit
.
class Food {
public:
Food() : m_fruit(new Fruit()) {}
Food(Fruit* f) : m_fruit(f) {}
void SetFruit(Fruit* f) { if(m_fruit != f) { delete m_fruit; m_fruit = f; } }
Fruit& GetFruit() { return *m_fruit; }
const Fruit& GetFruit() const { return *m_fruit; }
int Test() { return m_fruit->GetWeight(); }
private:
Fruit* m_fruit;
};
Другой вариант - для Food
сделать копию переданного Fruit
. Это сложно. В старые времена мы определяли Fruit::clone()
метод, который подклассы переопределяли бы:
class Fruit {
public:
virtual int GetWeight() { return 0; }
virtual Fruit* clone() const { return new Fruit(*this); }
};
class Apple : public Fruit {
public:
virtual int GetWeight() { return 2; }
virtual Fruit* clone() const { return new Apple(*this); }
};
class Banana : public Fruit {
public:
virtual int GetWeight() { return 3; }
virtual Fruit* clone() const { return new Banana(*this); }
};
Я не думаю, что вы можете сделать виртуальный конструктор так, как вам нужно, чтобы сделать его красивее.
Тогда класс Food
изменится на:
class Food {
public:
Food() : m_fruit(new Fruit()) {}
Food(const Fruit& f) : m_fruit(f.clone()) {}
void SetFruit(const Fruit& f) { delete m_fruit; m_fruit = f.clone(); }
Fruit& GetFruit() { return *m_fruit; }
const Fruit& GetFruit() const { return *m_fruit; }
int Test() { return m_fruit->GetWeight(); }
private:
Fruit* m_fruit;
};
При этой настройке ваш SomeFunction
будет работать, поскольку food1
больше не зависит от существования a
.