C ++. A practical example of using a member of polymorphic data

What is the best practice for using a member of polymorphic data in C ++? The simplest one I know just uses a simple pointer.

For example, if the item type is not polymorphic:

class Fruit {
  public:
    int GetWeight() { return 1; }
};

class Food {
  public:
    Food(Fruit f=Fruit()) : m_fruit(f) {}
    void SetFruit(Fruit f) { m_fruit = f; }
    Fruit GetFruit() { return m_fruit; }
    int Test() { return m_fruit.GetWeight(); }
  private:
    Fruit m_fruit;
};
// Use the Food and Fruit classes
Food food1; //global scope
void SomeFunction() {
  Fruit f;
  food1.SetFruit(f);
}
int main() {
  Fruit fruit1, fruit2;
  Food food2(fruit1);
  food2.SetFruit(fruit2);
  food2.SetFruit(Fruit());
  SomeFunction();
  food1.Test();
  food2.Test();
  return 0;
}

It is easy to use classes in many ways with minimal error.

Now, if we make Fruit the base class (use polymorphic), this is the easiest / best I can think of:

class Fruit {
  public:
    virtual int GetWeight() { return 0; }
};

class Apple : public Fruit {
  public:
    virtual int GetWeight() { return 2; }
};

class Banana : public Fruit {
  public:
    virtual int GetWeight() { return 3; }
};

class Food {
  public:
    Food(Fruit& f=defaultFruit) : m_fruit(&f) {}
    void SetFruit(Fruit& f) { m_fruit = &f; }
    Fruit& GetFruit() { return *m_fruit; }
    int Test() { return m_fruit->GetWeight(); }
  private:
    Fruit* m_fruit;
    static const Fruit m_defaultFruit = Fruit();
};
// Use the Food and Fruit classes
Food food1; //global scope
void SomeFunction() {
  Apple a;
  food1.SetFruit(a);
}

int main() {
  Apple a;
  Banana b;
  Food food2(a);
  food2.SetFruit(b);
  food2.SetFruit(Apple()); //Invalid ?!
  SomeFunction(); //Weakness: the food1.m_fruit points to invalid object now.
  food1.Test();   //Can the compiler detect this error? Or, can we do something to assert m_fruit in Food::Test()?
  food2.Test();
  return 0;
}

Is there a better way to do this? I try to keep it simple without using any new / delete. (Note: must have a default value)

UPDATE: Consider a more practical example:

class Personality {
public:
  void Action();
};
class Extrovert : public Personality {
  ..implementation..
};
class Introvert : public Personality {
  ..implementation..
};

class Person {
  ...
  void DoSomeAction() { personality->Action(); }
  ...
  Personality* m_personality;
};

, . ? , Personality. - /, /?

+3
3

. , -, ; , . :

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.

+3

new, . , , , , , . , .

boost:: any. . , Boost, , , , . , , /.

, Food Fruit , delete ~Food() ( , shared_ptr, scoped_ptr auto_ptr, ). , . ( : , , operator new.)

. , , , Fruit. clone() Fruit, Fruits .

+1

SetFruit() f m_fruit, , . f - , , SetFruit() . f . , m_fruit , .

, - :

class Food {
  public:
    Food(Fruit* f = &defaultFruit) : m_fruit(f) {}
    void SetFruit(Fruit* f) { m_fruit = f; }
    Fruit* GetFruit() { return m_fruit; }
    int Test() { return m_fruit->GetWeight(); }
  private:
    Fruit* m_fruit;
    static const Fruit m_defaultFruit;
};

, ( , ).

0

Source: https://habr.com/ru/post/1774446/


All Articles