Курс ООП в С презентация. ООП в с++(полный курс). Объекты и классы
Скачать 1.76 Mb.
|
НаследованиеОперация присваивания не наследуется и, поэтому ее также требуется явно определить. Деструкторы не наследуются, и если программист не описал в производном классе деструктор, он формируется по умолчанию и вызывает деструкторы всех базовых классов. В отличие от конструкторов, при написании деструктора производного класса в нем не требуется явно вызывать деструкторы базовых классов, это будет сделано автоматически. Для иерархии классов, состоящей из нескольких уровней, деструкторы вызываются в порядке, строго обратном вызову конструкторов: сначала вызывается деструктор класса, затем — деструкторы элементов класса, а потом деструктор базового класса. НаследованиеТеперь попробуем учесть отличия руководителя от просто работника, заключающиеся в особенности вычисления заработной платы. Метод get_salary() в таком случае должен возвращать не просто значение атрибута salary, определяющего тариф по ставке работника… const double employee::get_salary() { return salary; } …, а ещё и учитывать величину надбавки: const double manager::get_salary() { double add = 0; list for (i = Employers.begin(); i != Employers.end(); i++) { add += 0.03*(*i)->get_salary(); } return salary+add; } НаследованиеТаким образом, следует вызывать нужный метод в зависимости от того, объект какого класса нам встретился в ходе работы программы. Такое поведение, называемое полиморфным, реализуется с помощью механизма виртуальных методов. Для того чтобы иметь возможность переопределить поведение метода get_salary() в подклассе manager, мы объявили его в классе employee как виртуальный. Виртуальные методы Виртуальные методыДоступ к объектам иерархии классов лучше всего осуществляется через указатели на базовый тип. При наследовании со спецификатором public такому указателю можно присваивать адрес любого производного класса. Проблема заключается в том, что компилятор не будет знать, с каким именно классом связан указатель. Виртуальные методыНапример, мы имеем в наличии трех работников: двух подчиненных (A и B) и их руководителя C, составляющих множество E. Им назначена зарплата в 3300, 4400 и 5500 рублей соответственно. У нас стоит задача представить фактические доходы работников, которые будут определяться не только окладом. void main() { employee A, B; manager C; employee* E[3]; E[0] = &A; E[1] = &B; E[2] = &C; C.Employers.push_back(&A); C.Employers.push_back(&B); E[0]->set_salary(3300); E[1]->set_salary(4400); E[2]->set_salary(5500); for (i = 0; i < 3; i++) { cout << E[i]->get_salary() << endl; } } Виртуальные методыОтметим, что во время компиляции не будет известно, на какой объект указывает E[i], следовательно, класс будет определяться по типу указателя. Соответственно будет выбран и правильный метод для вычисления заработной платы. В C++ реализован механизм позднего связывания, когда разрешение ссылок на метод происходит на этапе выполнения программы в зависимости от конкретного типа объекта, вызвавшего метод. Этот механизм реализован с помощью виртуальных методов и рассмотрен в следующем разделе. Для определения виртуального метода используется спецификатор virtual: Правила описания и использования виртуальных методов: Если в базовом классе метод определен как виртуальный, метод, определенный в производном классе с тем же именем и набором параметров, автоматически становится виртуальным, а с отличающимся набором параметров – обычным. Виртуальные методы наследуются, т.е. переопределять их в производном классе требуется только при необходимости задать отличающиеся действия. Права доступа при переопределении изменить нельзя. Если виртуальный метод переопределен в производном классе, объекты этого класса могут получить доступ к методу базового класса с помощью операции доступа к области видимости. Виртуальный метод не может объявляться с модификатором static, но может быть объявлен как дружественный. Виртуальные методыМеханизм позднего связывания Для каждого класса (не объекта!), содержащего хотя бы один виртуальный метод, компилятор создает таблицу виртуальных методов (vtbl), в которой для каждого виртуального метода записан его адрес в памяти. Адреса методов содержатся в таблице в порядке их описания в классах. Адрес любого виртуального метода имеет в vtbl одно и то же смещение для каждого класса в пределах иерархии. Каждый объект содержит скрытое дополнительное поле ссылки на vtbl, называемое vptr. Оно заполняется конструктором при создании объекта (для этого компилятор добавляет в начало тела конструктора соответствующие инструкции). На этапе компиляции ссылки на виртуальные методы заменяются на обращения к vtbl через vptr объекта, а на этапе выполнения в момент обращения к методу его адрес выбирается из таблицы. Таким образом, вызов виртуального метода, в отличие от обычных методов и функций, выполняется через дополнительный этап получения адреса метода из таблицы. Это несколько замедляет выполнение программы. |