Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Порядок вызова конструкторов⇐ ПредыдущаяСтр 12 из 12
При использовании множественного наследования, в протоколе производного класса необходимо вызывать конструктор базовых классов для инициализации полей данных, наследуемых от двух или более базовых классов, и инициализировать различные элементы объектов. Четко определенный порядок инициализации приведен ниже:
class Parent1 { int p1; public: Parent1(void) { cout < < “ Construct Parent1 free parameter”; p1=0; } Parent1(int ap): p1(ap) { cout < < “Construct Parent1 1 parameter”; } ~Parent1(void) { cout < < “ destruct Parent1”; } }; class Parent2 { int p2; public: Parent2(void) { cout < < “ Construct Parent2 free parameter”; p2=0; } Parent2(int ap): p2(ap) { cout < < “Construct Parent2 1 parameter”; } ~Parent2(void) { cout < < “ destruct Parent2”; } }; class Parent3 { int p3; public: Parent3(void) { cout < < “ Construct Parent3 free parameter”; p3=0; } Parent3(int ap): p3(ap) { cout < < “Construct Parent3 1 parameter”; } ~Parent3(void) { cout < < “ destruct Parent3”; } }; class Member { int m; public: Member(void) { cout < < “ Construct Member free parameter”; m=0; } Member(int ap): m(ap) { cout < < “Construct Member 1 parameter”; } ~Member(void) { cout < < “ destruct Member”; } }; class Child: public Parent3, public Parent2, public Parent3 { Member mem1, mem2; public: Child(void) { cout < < “ construct child free parameter”; } Child(Member achildMember): childMember(achildMember) { cout < < “ Construct Child with 1 parameter”; } Child(int v1, int v2, int v3, int m1, int m2): mem2(m1), Parent1(v1), Parent3(v3), Parent2 (v2), mem1(m2){ cout < < “ construct child with 3 parameter”; } ~Child(void) { cout < < “destruct Child”; } }; main() { Member m(16); // Construct Member with 1 parameter // destruct Member Child child1; // Construct Parent3 free parameter // Construct Parent2 free parameter // Construct Parent1 free parameter // Construct Member free parameter // Construct Member free parameter // construct child free parameter // destruct Child // destruct Member // destruct Member //destruct Parent1 // destruct Parent2 // destruct Parent3
Child child2(m); // Construct Parent3 free parameter // Construct Parent2 free parameter // Construct Parent1 free parameter // Construct Member free parameter // Construct Child with 1 parameter // destruct Child // destruct Member // destruct Member // destruct Parent1 // destruct Parent2 // destruct Parent3
Child child3(10, 20, 30, 40, 50); // Construct Parent3 with 1 parameter // Construct Parent2 free parameter // Construct Parent1 with 1 parameter // Construct Member 1 parameter 50 // Construct Member 1 parameter 40 // construct child with 3 parameter // destruct Child // destruct Member // destruct Member // destruct Parent1 // destruct Parent2 // destruct Parent3 } Виртуальные базовые классы В прямом ациклическом графе наследования класс может появиться более чем один раз. Рассмотрим ПАГ множественного наследования, приведенный на рис. Элементы данных (экземпляры переменных) класса Parent появляются дважды в классе GrandChild. Первый набор наследуется через Child1, второй - через Child2. Такое наследование бывает нежелательно. Виртуальные базовые классы обеспечивают механизм для избежания дублирования элементов в классе, таком как CrandChild Допустим, класс Parent на самом деле называется Vehicle (транспортное средство). В его протоколе содержится закрытое поле данных int topSpeed. Класс Child1 на самом деле называется Boat(Корабль), а класс Child2 -называется Plane (самолет). Наконец, класс GrandChild на самом деле называется SeaPlane. Для SeaPlane желательно наследовать Boat:: topSpeed и Plane:: topSpeed. Объект класса SeaPlane имеет различную предельную скорость в зависимости от того, действует он как корабль или самолет. С другой стороны, допустим, класс Parent назван DomesticAnimal (домашнее животное), класс Child1 назван Cow (корова), класс Child2 назван Buffalo (бык), а класс GrandChild назван Beefalo(теленок). Допустим, протокол класса DomesticAnimal включает экземпляры переменных int weight, float price, char color[20]. Нежелательно, чтобы протокол класса Beefalo имел по два экземпляра переменных weight, price, color. Избежать дублирования позволяет использование виртуальных базовых классов.
class DomesticAnimal { protected: int weight; float price; char color[20]; public: DomesticAnimal(void) {weight=0; price=0.; strcpy(color, ”none”); } DomesticAnimal(int aweight, float aprice, char *acolor) { weight=aweight; price=aprice; strcpy(color, acolor); } virtual void print(void) { cout < < weight < < price < < color; } }; class Cow: public virtual DomesticAnimal { public: Cow(void) { } Cow(int aweight, float aprice, char *acolor) { weight=aweight; price=aprice; strcpy(color, acolor); } void print(void) { cout < < “ Cow has propeties”; DomesticAnimal:: print(); } }; class Buffalo: public virtual DomesticAnimal { public: Buffalo(void) { } Buffalo(int aweight, float price, char *acolor) { weight=aweight; price=aprice; strcpy(color, acolor); } void print(void) { cout< < “ Buffalo has propeties”; DomesticAnimal:: print(); } }; class Beefalo: public Cow, public Buffalo { public: Beefalo(int aweight, float aprice, char *acolor) { weight=aweight; price=aprice; strcpy(color, acolor); } void print(void) { cout < < “ beefalo has propeties”; DomesticAnimal:: print(); } }; main() { Cow aCow(1400, 375.0, ”black and white”); // void const Domestic // const par Cow Beefalo aBeefalo(1700, 525.0, ”Brown and black”); // void cons Domestic // void const Cow // void const Buffalo // const par Beefalo DomesticAnimal& myCow=aCow; DomesticAnimal& myBeefalo=aBeefalo; my.Cow.print(); myBeefalo.print(); }
Результат работы Cow has propeties weight=1400 price=375.0 color=black and white beefalo has propeties weight=1700 price=525.0 color=brown and white Код приведенной выше программы решает проблему класса Beefalo, который наследует поля данных weight, price, color. Объекты класса Beefalo имеют по одному полю данных для веса, цены и цвета.
Ключевое слово virtual в классе Cow и классе Buffalo предотвращает многократное копирование полей данных weight, price, color из предков класса Beefalo.
Вопрос: 1. Что, если из объявлений классов Cow и Buffalo убрать ключевое слово virtual.
Компилятор выдаст сообщение об ошибке. В Beefalo унаследовано несколько копий полей weight, price, color, следовательно, конструктор с несколькими параметрами в классе Beefalo становится недействительным. 2. Что, если конструктор класса Cow заменить на Cow(int aweight, float aprice, char *acolor): DomesticAnimal(aweight, aprice, acolor) { } Вместо void конструктора DomesticAnimals вызовется конструктор с параметрами. 3. Что, если конструктор с параметрами класса Beefalo заменить на Beefalo(int aweight, float aprice, char *acolor): DomesticAnimal(aweight, aprice, acolor){} Все будет работать нормально. Вначале вызовется конструктор базового виртуального класса с параметрами, затем конструкторы наследуемых классов без параметров. Вызова конструктора без параметра виртуального базового класса не будет.
Другой пример: class W{ public: virtual void f(void) { cout < < “ W:: f”; } virtual void g(void) {cout < < “ W:: g”; } virtual void h(void) {cout < < “ W:: h”; } virtual void k(void) {cout < < “ W:: k”; } }; class A: public virtual W { public: void g(void) { cout < < “ A:: g”; } }; class B: public virtual W { public: void f(void) { cout < < “ B:: f”; } }; class C: public A, public B, public virtual W { public: void h(void) { cout < < “C:: h”; } void f(void) { B:: f(); } void g(void) { A:: g(); } }; main() { C *pc=new C; pc-> f(); // C:: f() ( B:: f) pc-> g(); // C:: g() ( A:: g) pc-> h(); // C:: h ((A *)pc)-> f(); // C:: f (B:: f) ((W *)pc)-> f(); // C:: f (B:: f)
B *pb=new B; pb-> f(); // B:: f pb-> g(); // W:: g ((W *)pb)-> f(); // B:: f
A *pa=new A; pa-> f(); // W:: f pa-> g(); // A:: g ((W *)pa)-> g(); // A:: g }
При вызове ((A *)pc)-> f() выполняется функция f класса С. Тоже происходит и при вызове ((W *)pc)-> f().Таблица виртуальных функций использует определение f в классе С. Это демонстрирует то, что при вызове “верхней” виртуальной функции по одному пути ПАГа может закончиться вызовом функции по другому пути.
Вопрос 1. Что, если в Классе А определить функцию член f. Последняя часть работы программы измениться A:: f A:: g A:: g
Если виртуальный базовый класс и производный класс разделяют имя какого-либо поля, функции-члена или перечисления, то имя в производном классе скрывает имя в виртуальном базовом классе.
class V { public: int i; void f(); }; class A: virtual public V {public: int i; int f(); }; class B: virtual public V { }; class C: public A, public B { void g() { i=f(); } // Правильно A:: i и A:: f() скрывают V:: i V:: f() }; Их конструкторы вызываются конструктором последнего класса в цепочке производных классов. V:: V(int n): i(n) {} A:: A(int i): V(i) {} B:: B(int i): V(i) {} C:: C(int i): V(i), A(i), B(i) {} В объявлении класса могут быть смешаны с невиртуальными базовыми классами. Виртуальные базовые классы могут вызывать нежелательные множественные вызовы функций-членов в виртуальном базовом классе. ckass V { public: void f(); }; class A: virtual public V { public: void f() { V:: f(); } }; class B: virtual public V { public: void f() { V:: f(); } }; class C: public A, public B { public: void f() { A:: f(); B:: f(); } // V:: f() вызывается дважды }; Для преодоления указанного эффекта можно определить функцию real_f(), которая выполняет действия, специфичные для функции f() данного класса. Тогда функция f() будет выполнять последовательные вызовы сначала функции real_f(), а затем - функции f(). class V { protected: void real_f() {} public: void f() { real_f(); } }; class A: virtual public V { protected: void real_f() {} public: void f() { real_f(); V:: f(); } }; class B: virtual public V { protected: void real_f() { } public: void f() { real_f(); V:: f(); } }; class C: public A, public B { protected: void real_f() {} public: void f() { real_f(); A:: reaal_f(); B:: real_f(); V:: real_f(); } }; Задания на лабораторные работы по Объектно-ориентированному программированию, множественное наследование
Вариант 1. Создать иерархию типов, описывающую - студента, отца семейства и студента-отца семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую - человека, студента, отца семейства и студента-отца семейства. Использовать виртуальные базовые классы. Вариант 2. Создать иерархию типов, описывающую работника и отца-семейства, и работника-отца семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2 Создать иерархию типов, описывающую - человека, работника, отца семейства и работника-отца семейства. Использовать виртуальные базовые классы. Вариант 3. Создать иерархию типов - файл для чтения, файл для записи и файл для чтения и записи. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую файл, файл для чтения, файл для записи и файл для чтения и записи. Использовать виртуальные базовые классы. Вариант 4. Создать иерархию типов, описывающую работника и женщину, и работника-женщину семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую человека, работника и женщину, и работника-женщину семейства. Использовать виртуальные базовые классы. Вариант 5. Создать иерархию типов, описывающую операционную систему и прикладное программное обеспечение, и Windows NT как операционную систему и прикладное программное обеспечение. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую программное обеспечение, операционную систему и прикладное программное обеспечение, и Windows NT как операционную систему и прикладное программное обеспечение. Использовать виртуальные базовые классы. Вариант 6. Создать иерархию типов, описывающую данные - сигнал, данные результат обработки и данные, как результат обработки сигнала и представляющие собой сигнал. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую данные - сигнал, данные результат обработки и данные, как результат обработки сигнала и представляющие собой сигнал. Использовать виртуальные базовые классы. Вариант 7. Создать иерархию типов - море, залив и бухта.. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов - соленная вода, море, залив и бухта. Использовать виртуальные базовые классы. Вариант 8. Создать иерархию типов - корабль, пассажирский транспорт и пассажирский корабль. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов - транспорт, корабль, пассажирский транспорт и пассажирский корабль. Использовать виртуальные базовые классы. Вариант 9. Создать иерархию типов - машина, пассажирский транспорт и автобус. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов - машина, пассажирский транспорт и автобус. Использовать виртуальные базовые классы. Вариант 10. Создать иерархию типов, описывающую - студента, отца семейства и студента-отца семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую - человека, студента, отца семейства и студента-отца семейства. Использовать виртуальные базовые классы. Вариант 11. Создать иерархию типов, описывающую работника и отца-семейства, и работника-отца семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2 Создать иерархию типов, описывающую - человека, работника, отца семейства и работника-отца семейства. Использовать виртуальные базовые классы. Вариант 12. Создать иерархию типов - файл для чтения, файл для записи и файл для чтения и записи. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую файл, файл для чтения, файл для записи и файл для чтения и записи. Использовать виртуальные базовые классы. Вариант 13. Создать иерархию типов - корабль, пассажирский транспорт и пассажирский корабль. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов - транспорт, корабль, пассажирский транспорт и пассажирский корабль. Использовать виртуальные базовые классы. Вариант 14. Создать иерархию типов, описывающую операционную систему и прикладное программное обеспечение, и Unix как операционную систему и прикладное программное обеспечение. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток. Задание 2. Создать иерархию типов, описывающую программное обеспечение, операционную систему и прикладное программное обеспечение, и Unix как операционную систему и прикладное программное обеспечение. Использовать виртуальные базовые классы.
ЭКЗАМЕНАЦИОННЫЕ ВОПРОСЫ
1. Общая характеристика языка С и его характерные отличия от языка PASCAL. 2. Структура программы на языке С. Подключение библиотек, Организация ввода-вывода с помощью библиотеки iostream. 3. Модуль в языке С. Организация многофайловой программы, заголовочные файлы, директива #include, прототипы функций. 4. Оператор присваивания и оператор ветвления. Особенности оператора присваивания и вычисления условий в языке С. Примеры операторов присваивания и ветвления. 5. Объявление массивов с языке С. Организация циклов. Цикл с предусловием и постусловием. Цикл for и его связь с циклом while. Примеры. 6. Оператор переключатель. Инструкция break. Примеры применения оператора переключателя. 7. Числовые типы данных языка С. Целочисленные (десятичные, восьми и шестнадцатиричные) и действительные константы. Именованные константы и способы их задания в языке С. 8. Перечисленный тип в языке С. Особенности, возможности и примеры его использования. 9. Понятие блока в языке С. Объявления и инициализация переменных и массивов в С. 10. Обзор операций языка С. Приоритеты операций. Операции низкого и высокого уровней. Примеры операций. 11. Выражения в языке С. Правила вычисления выражений. Приоритеты операций и правило ассоциативности. Приведение типов в С и С++. Операция последования (скобки). 12. Символьный тип в языке С. Символьные константы. Представление строк в С. Библиотека string. Примеры функций библиотеки string. 13. Указатели и ссылки в языке С. Константные указатели и ссылки. Операции с указателями и ссылками. 14. Массив как указатель в языке С. Особенности индексации массива при записи кода. Массив как параметр функции. Многомерные массивы. 15. Функции в языке С. Объявление, описание и вызов. Особенности передачи параметров (по значению, ссылке, указателем, константной ссылке). Перегрузка функций и параметры по умолчанию. 16. Функции в языке С. Встраиваемые функции и макросы. Передача функции как параметр. Функция как указатель на функцию. Массив указателей на функции. 17. Структуры в языке С. Объявление типа и переменных. Использование элементов структур. Вложенные структуры и массивы. Примеры построения вложенных структур и массивов. 18. Объединения в языке С. Объявление типа и переменных. Использование элементов объединений. Битовые поля. 19. Классы и типы памяти. Время жизни и область видимости объектов. Локальные и глобальные объекты. Механизм управления стеком. 20. Классы и типы памяти. Время жизни и область видимости объектов. Локальные и глобальные объекты. Механизм управления кучей. 21. Форматный вывод и ввод. Функции printf и scanf библиотеки stdio. 22. Форматные преобразования в памяти. Функции sprintf и sscanf библиотеки stdio. 23. Работа с текстовыми файлами. Функции fopen, fclose, fprintf, fscanf библиотеки stdio. 24. Работа с записеориентированными файлами. Функции fopen, fclose, fprintf, fscanf библиотеки stdio. 25. Работа с бинарными файлами. Функции fopen, fclose, fwrite, fread, fseek библиотеки stdio. 26. Технологические основы языков программирования высокого уровня. Структурное и модульное программирование. 27. Технологические основы языков программирования высокого уровня. Простые и сложные задачи. Причины возникновения сложности. Решение проблемы сложности задач. 28. ООП и объектная модель. Основные принципы объектной модели. 29. Анализ, проектирование и программирование. Объектный подход, алгоритмическая и объектно-ориентированная декомпозиция. Достоинства и недостатки ООП. 30. Абстрактные типы данных. Понятие класса. Инкапсуляция. Объявление класса. Поля и методы. Секции public и private. Скрытие данных. 31. Объявление класса. Поля и методы. Секции public и private. Скрытие данных. Пример разработки класса “Комплексное число”. Реализация методов класса. Встроенные методы. 32. Константные поля. Константные методы. Использование константных ссылок в списке параметров методов класса. Пример разработки класса “Комплексное число”. 33. Способы создания объектов. Доступ к данным и методам объекта. Указатель this. 34. Статическое и динамическое создание объектов внутри методов. Ссылки в заголовках методов. Примеры. 35. Создание объектов. Конструкторы. Виды конструкторов. 36. Конструктор копирования. Пример разработки конструктора копирования. 37. Уничтожение объектов. Деструкторы. 38. Статические поля и методы класса. Дружественные функции и классы. 39. Пример разработки класса “Вектор”. Реализация операций без использования перегрузки. 40. Перегрузка операций. Особенности перегрузки для унарных, бинарных операций. Перегрузка операции []. 41. Перегрузка операций. Перегрузка операции присваивания. Операция присваивания и конструктор копирования. 42. Суть проблемы моделирования. Инкапсуляция, модульность и иерархия как средства решения проблемы. Виды иерархий. Наследование и агрегация. Реализация агрегации в C++. Пример. 43. Наследование в C++. Простое (одиночное) наследование. Public, private и protected-наследование. Некоторые правила наследования. 44. Наследование в C++. Простое (одиночное) наследование. Пример последовательного проектирования иерархии классов геометрических фигур. Перекрытие (замещение) методов. 45. Раннее и позднее связывание. Механизм виртуальных методов. 46. Механизм виртуальных методов. Применение виртуальных методов для разработки классов “Точка” и “Круг”. 47. Чисто виртуальные методы и абстрактные классы. Абстрактный класс в примере “Геометрические фигуры”. 48. Множественное наследование. Виртуальное наследование. 49. Перегрузка функций в C++. Сигнатура. Алгоритм проверки соответствия сигнатуре. 50. Шаблоны функций. Шаблоны классов. Инстанцирование и специализация.
Популярное: |
Последнее изменение этой страницы: 2016-07-14; Просмотров: 866; Нарушение авторского права страницы