Освой самостоятельно С++ за 21 день.
Шрифт:
85:
86: protected:
87: COLOR itsColor;
88: };
89:
90: int main
91: {
92: Animal *pAnimal=0;
93: int choice;
94: bool fQuit = false;
95:
96: while (1)
97: {
98: cout << "(1)Dog (2)Horse (3)Fish(0)Quit: ";
99: cin >> choice; 100:
101: switch (choice)
102: {
103: case 1: pAnimal = new Dog(5,Brown);
104: break;
105: case 2: pAnimal = new Horse(4,Black);
106: break;
107: case 3: pAnimal = new
108: break;
109: default: fQuit = true
110: break;
111: }
112: if (fQuit)
113: break;
114:
115: pAnimal->Speak;
116: pAnimal->Eat;
117: pAnimal->Reproduce;
118: pAnimal->Move;
119: pAnimal->Sleep;
120: delete pAnimal;
121: cout << "\n";
122: }
123: return 0;
124: }
Результат:
(1)Dog (2)Horse (3)Bird (0)Quit: 1
Animal constructor. . .
Mammal constructor...
Dog constructor...
Woof!...
Dog eating. . .
Dog reproducing....
Dog running...
Dog snoring...
Dog destructor...
Mammal destructor...
Animal destructor...
(1)Dog (2)Horse (3)Bird (0)Quit: 0
Анализ:
Класс Mammal производится от Animal в строках 29—37 и не содержит никаких данных. В нем замещается функция Reproduce, чтобы задать способ размножения, общий для всех млекопитающих. Класс Fish производится непосредственно от класса Animal, поэтому функция Reproduce в нем замещается иначе, чем в классе Mammal (и это соответствует реальности).
Во всех других классах, производимых от класса Mammal, теперь нет необходимости замещать общий для всех метод Reproduce, хотя при желании это можно сделать для определенного класса, как, например, в нашей программе это было сделано в строке 83 для класса Dog. Все остальные чистые виртуальные функции были замещены в классах Fish, Horse и Dog, поэтому для каждого из них можно создавать соответствующие объекты.
В теле программы используется указатель класса Animal, с помощью которого делаются ссылки на все объекты производных классов. В зависимости от того, с каким объектом связан указатель в текущий момент, вызываются соответствующие виртуальные функции.
При попытке создать объекты для классов абстрактных типов данных Animal или Mammal компилятор покажет сообщение об ошибке.
Когда следует использовать абстрактные типы данных
В одних примерах программ, рассмотренных нами ранее, класс Animal являлся абстрактным типом данных, в других — нет. В каких же случаях нужно объявлять класс как абстрактный тип данных?
Нет никаких правил, которые требовали бы объявления класса как абстрактного. Программист принимает решение о создании абстрактного типа данных, основываясь на том, какую роль играет этот класс в программе. Так, если вы хотите смоделировать виртуальную ферму или зоопарк, то имеет смысл класс Animal объявить как абстрактный и для создания объектов производить от него другие классы, такие как Dog.
Если же вы хотите смоделировать виртуальную псарню, то теперь класс Dog будет абстрактным, от которого можно производить подклассы, представляющие разные породы собак. Количество уровней абстрактных классов следует выбирать в зависимости от того, насколько детально вы хотите смоделировать реальный объект или явление.
Рекомендуется:Используйте абстрактные типы данных для создания общего интерфейса для всех производных классов. Обязательно замещайте в производных классах все чистые виртуальные функции. Объявляйте все функции, которые нужно замещать в производных классах, как чистые виртуальные функции.
Не рекомендуется:Не пытайтесь создать объектабстрактного класса.
Логика использования абстрактных классов
В последнее время в программировании на C++ активно используется концепция создания абстрактных логических конструкций. С помощью таких конструкций можно находить решения для многих общих задач и создавать при этом программы, которые легко читаются и документируются. Рассмотрим пример создания логической конструкции с использованием наследования классов.
Представим, что нужно создать класс Timer, который умеет отсчитывать секунды. Такой класс может иметь целочисленную переменную-член itsSeconds, а также метод, осуществляющий приращение переменной itsSeconds.
Теперь предположим, что программа должна отслеживать и сообщать о каждом изменении переменной itsSeconds. Первое решение, которое приходит на ум, — это добавить в класс Timer метод уведомления об изменении переменной-члена. Но логически это не совсем верно, так как программа уведомления может быть достаточно сложной и по сути своей не является логической частью программы отсчета времени.
Гораздо логичнее рассматривать программу отслеживания и информирования об изменении переменной как абстрактный класс, который в равной степени может использоваться как с программой отсчета времени, так и с любой другой программой с периодически изменяющимися переменными.
Таким образом, лучшим решением будет создание абстрактного класса обозревателя Observer с чистой виртуальной функцией Update.
Теперь создадим второй абстрактный класс — Subject. Он содержит массив объектов класса Observer. Кроме того, в нем объявлены два дополнительных метода: Register, который регистрирует объекты класса Observer, и Notify, который отслеживает изменения указанной переменной.