Кой е най-добрият практически модел за използване на полиморфен член от данни в C++? Най-простият, който познавам, е използването на обикновен указател.
Например, ако типът член на данните не е полиморфен:
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;
}
Лесно е да използвате класовете по много начини с минимална възможност за грешки.
Сега, ако направим Fruit базов клас (използваме полиморфен), това е най-простият/най-добрият, за който мога да се сетя:
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;
}
Има ли по-добър начин да направите това? Опитвам се да го запазя просто, без да използвам оператор за ново/изтриване. (Забележка: трябва да може да има стойност по подразбиране)
АКТУАЛИЗАЦИЯ: Нека разгледаме по-практичен пример:
class Personality {
public:
void Action();
};
class Extrovert : public Personality {
..implementation..
};
class Introvert : public Personality {
..implementation..
};
class Person {
...
void DoSomeAction() { personality->Action(); }
...
Personality* m_personality;
};
Целта е да има хора с различни характери и да се улесни добавянето на повече Личност чрез подкласиране. Какъв е най-добрият начин за прилагане на това? Тъй като логично се нуждаем само от един обект за всеки тип Личност, няма много смисъл Човек да копира или да поеме собственост върху обекта Личност. Може ли да има някакъв различен подход/дизайн, който не изисква от нас да се занимаваме с проблема с копирането/собствеността?