Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
САОД_ответы_catsto_NEW.doc
Скачиваний:
17
Добавлен:
16.04.2019
Размер:
365.57 Кб
Скачать

Virtual string Iam(){return "furniture";}

Теперь пример сработает как ожидалось!

Почему это произошло? Все дело в так называемом “позднем связывании”. Вспомним еще раз, что происходит при компиляции и сборке программы. Компилятор готовит отдельные модули, затем компоновщик связывает эти модули в единую программы. Там где стоит вызов Iam() подставляется адрес конкретной функции. На момент компоновки об этой функции известно только что это метод CFurniture, его-то адрес и будет стоять в результирующей программе. Поэтому, какие объекты фактически были добавлены в список не играет роли. Это так называемое “статическое связывание”.

При позднем связывании компилятор “знал”, что вызывается виртуальный метод. Поэтому нельзя подставлять при вызове Iam вызов конкретной функции, а нужно подставить код поиска ее в таблице виртуальных методов. У каждого класса имеется собственная таблица виртуальных методов. В нее помещаются все методы, отмеченные как virtual. Если потомок перекрывает виртуальный метод, то в таблице потомка указывается иной адрес этого метода.

Таким образом, поиск нужной функции выполняется во время исполнения программы:

- У объекта выясняется адрес таблицы виртуальных методов его класса.

- В этой таблице ищется адрес соответствующего метода;

- Найденный метод вызывается.

Это и есть позднее связывание.

Так полиморфизм позволил продвинуться к разработке обобщенных программ, которые могут работать с абстрактными понятиями, которые обобщают множество конкретных типов.

Резюме.

Полиморфизм – важное средство объектно-ориентированного программирования. Основное его предназначение – обеспечить абстракции понятий и операций, которые могут различаться для конкретных классов.

Важнейший вид полиморфизма – полиморфизм виртуальных методов. Он позволяет хранить и обрабатывать специфическим для каждого класса образом объекты одной иерархии классов в одном контейнере. Перечислим, как это делается:

- методы, различающиеся для потомков, в классе предке объявляются виртуальными;

- указатели на динамически созданные объекты помещаются в контейнер для указателей на старший класс иерархии.

В этом случае, для каждого объекта будут вызываться методы именно его фактического класса, а не методы предка.

Интерфейсы и абстрактные классы

Что если мы хотим объявить класс, от которого будет построена целое семейство потомков, но сам класс реализовывать нет смысла – объекты такого типа бессмысленны и создаваться не могут. Примерами могут быть классы CFigure и CFurnuture. Невозможно нарисовать фигуру вообще или предмет мебели. Это всегда их конкретизация, прямоугольник, стол и т.п.

Для отражения такой картины в C++ могут объявляться абстрактные методы. Вот пример объявления.

class CFigure {

public:

virtual void Draw(CWnd *hWnd) = 0;

};

Т.е. мы знаем, что метод Draw будет переопределен в каждом классе – потомке CFigure. Поэтому он объявлен как virtual. А на то, что его реализация отсутствует указывает = 0 после объявления.

Классы, у которых нет полей данных, а все методы виртуальные и абстрактные называются абстрактными классами или интерфейсами. Интерфейсам не нужны конструкторы и деструкторы – объекты этого типа создаваться не могут. Их единственная роль – задать интерфейс использования потомков.