Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Порядок вызова конструкторов



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

  • Инициализация осуществляется в порядке, определяемом порядком объявления
  • Члены инициализируются в порядке объявления
  • Void-конструкторы базовых классов, которые явно не указаны в инициализирующем списки, вызываются после конструкторов явно инициализируемых базовых классов, в том порядке, в котором они следуют в объявлении класса. Эти void-конструкторы вызываются перед любыми конструкторами полей данных.

 

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 имеют по одному полю данных для веса, цены и цвета.

 

  • Виртуальные базовые классы инициализируются (вызывается void-конструктор) перед любыми не виртуальными базовыми классами и в том порядке, в котором они появляются в ПАГе наследования при просмотре его снизу-вверх и слева направо.
  • Если виртуальный базовый класс имеет хотя бы один конструктор, то он должен иметь void-конструктор.

Ключевое слово 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.
Задание 1.

Создать иерархию типов, описывающую - студента, отца семейства и студента-отца семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов, описывающую - человека, студента, отца семейства и студента-отца семейства. Использовать виртуальные базовые классы.

Вариант 2.
Задание 1.

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

Задание 2

Создать иерархию типов, описывающую - человека, работника, отца семейства и работника-отца семейства. Использовать виртуальные базовые классы.

Вариант 3.
Задание 1.

Создать иерархию типов - файл для чтения, файл для записи и файл для чтения и записи. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов, описывающую файл, файл для чтения, файл для записи и файл для чтения и записи. Использовать виртуальные базовые классы.

Вариант 4.
Задание 1.

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

Задание 2.

Создать иерархию типов, описывающую человека, работника и женщину, и работника-женщину семейства. Использовать виртуальные базовые классы.

Вариант 5.
Задание 1.

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

Задание 2.

Создать иерархию типов, описывающую программное обеспечение, операционную систему и прикладное программное обеспечение, и Windows NT как операционную систему и прикладное программное обеспечение. Использовать виртуальные базовые классы.

Вариант 6.
Задание 1.

Создать иерархию типов, описывающую данные - сигнал, данные результат обработки и данные, как результат обработки сигнала и представляющие собой сигнал. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов, описывающую данные - сигнал, данные результат обработки и данные, как результат обработки сигнала и представляющие собой сигнал. Использовать виртуальные базовые классы.

Вариант 7.
Задание 1.

Создать иерархию типов - море, залив и бухта.. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов - соленная вода, море, залив и бухта. Использовать виртуальные базовые классы.

Вариант 8.
Задание 1.

Создать иерархию типов - корабль, пассажирский транспорт и пассажирский корабль. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов - транспорт, корабль, пассажирский транспорт и пассажирский корабль. Использовать виртуальные базовые классы.

Вариант 9.
Задание 1.

Создать иерархию типов - машина, пассажирский транспорт и автобус. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов - машина, пассажирский транспорт и автобус. Использовать виртуальные базовые классы.

Вариант 10.
Задание 1.

Создать иерархию типов, описывающую - студента, отца семейства и студента-отца семейства. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов, описывающую - человека, студента, отца семейства и студента-отца семейства. Использовать виртуальные базовые классы.

Вариант 11.
Задание 1.

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

Задание 2

Создать иерархию типов, описывающую - человека, работника, отца семейства и работника-отца семейства. Использовать виртуальные базовые классы.

Вариант 12.
Задание 1.

Создать иерархию типов - файл для чтения, файл для записи и файл для чтения и записи. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов, описывающую файл, файл для чтения, файл для записи и файл для чтения и записи. Использовать виртуальные базовые классы.

Вариант 13.
Задание 1.

Создать иерархию типов - корабль, пассажирский транспорт и пассажирский корабль. Классы должны конструкторы, включая конструктор копирования, виртуальные деструкторы, перегруженные функции вывода в поток и ввода в поток.

Задание 2.

Создать иерархию типов - транспорт, корабль, пассажирский транспорт и пассажирский корабль. Использовать виртуальные базовые классы.

Вариант 14.
Задание 1.

Создать иерархию типов, описывающую операционную систему и прикладное программное обеспечение, и 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; Просмотров: 817; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.131 с.)
Главная | Случайная страница | Обратная связь