Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
_24-29_ООП_MatiasRust_DC_CT_LE_LcMS.doc
Скачиваний:
2
Добавлен:
01.03.2025
Размер:
122.88 Кб
Скачать

Конструкторы и деструкторы производных классов.

Допустим, у нас есть три класса: базовый класс A – «точка», наследуемый от него класс B – «окружность», и наследуемый от «окружности» класс C – «колобок».

Создаваться «колобок» будет так: точка → окружность → колобок

Уничтожаться же в обратном порядке: колобок → окружность → точка

Пример:

class string{... string (char*); ~string (); };

class Base{... Base (int); ~Base (); };

class Derived: public Base {...

Base b;

string s;

Derived (char*, int);

~Derived (); };

Перед обращением к собственно конструктору класса Derived необходимо, во-первых, создать подобъект типа Base, во-вторых, члены b и s. Поскольку для их создания нужно обратиться к конструкторам соответствующих классов, мы должны им всем передать необходимые списки аргументов:

Derived::Derived (char *str, int len): Base(len), b(len+1), s(str) {...}

В этом случае при создании объекта типа Derived сначала будет создан подобъект типа Base. При этом будет вызван конструктор Base::Base(int) с аргументом len. Затем будут созданы объекты b и s в том порядке, в котором они указаны в определении класса Derived. После этого будет выполнен конструктор Derived::Derived (). Деструкторы будут вызваны в обратном порядке, т.е.: сначала деструктор класса Derived, потом деструкторы объектов b и s, затем деструктор базового класса Base.

Полиморфизм и виртуальные функции, раннее и позднее связывание.

Одно из самых коротких и выразительных определений полиморфизма таково: полиморфизм - это функциональная возможность, позволяющая старому коду вызвать новый. Это свойство дает возможность расширять и совершенствовать программную систему, не затрагивая существующий код. Осуществляется такой подход с помощью механизма виртуальных функций.

Раннее (статическое) связывание. Во время раннего связывания вызывающий и вызываемый методы связываются при первом удобном случае, обычно при компиляции.

Позднее (динамическое) связывание. При позднем связывании вызываемого метода и вызывающего метода они не могут быть связаны во время компиляции. Поэтому реализован специальный механизм, который определяет, как будет происходить связывание вызываемого и вызывающего методов, когда вызов будет сделан фактически.

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

Виртуальный метод – это метод, который, будучи описан в потомках, замещает собой соответствующий метод везде, даже в методах, описанных для предка, если он вызывается для потомка.

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

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

Класс "транспортное средство"

class vehicle {

public: virtual void message() {cout<< "Транспортное средство\n";}};

Класс "легковая машина"

class car : public vehicle {

public: void message() {cout << "Легковая машина\n";}};

Класс "грузовая машина"

class truck : public vehicle {}; // нету метода для потомка

Класс "лодка"

class boat : public vehicle {

public: void message() {cout << "Лодка\n";}};

void main(){

vehicle *A;

A = new vehicle; A->message(); delete A;

A = new car; A->message(); delete A;

A = new truck; A->message(); delete A;

A = new boat; A->message(); delete A;}

Результаты работы программы (вывод на экран):

Транспортное средство

Легковая машина

Транспортное средство

Лодка

Не смотря на то, что переменная A является указателем на базовый класс vehicle, для нее вызываются методы message ее классов-потомков.

Стандартная библиотека потоковых классов ввода/вывода iostream.

Операции вставки/извлечения <</>> . Объекты cin и cout. Форматирование данных, флаги и манипуляторы потоков. Перегрузка операций << / >> для нестандартных типов данных.

Библиотека потоковых классов ввода/вывода iostream.

В отличие от стандартной библиотеки (в которой находятся средства, например, для работы со строками, или математические функции), унаследованной компиляторами языка С++ от языка С, библиотека ввода-вывода С++ является не библиотекой функций, а библиотекой классов. Это первая "промышленная" библиотека классов, разработанная для распространения совместно с компиляторами.

Библиотека потоковых классов построена на основе двух базовых классов: ios и streambuf.

Объекты cin и cout

Аналогами потоков stdin, stdout, stderr являются классы cin, cout и cerr. Эти три потока открываются автоматически. Поток cin связан с клавиатурой, а cout, cerr – с дисплеем.

– cin – объект класса istream, связанный со стандартным буферизированным входным потоком (обычно клавиатура консоли);

– cout – объект класса ostream, связанный со стандартным буферизированным выходным потоком (обычно дисплей консоли);

– cerr – объект класса ostream, связанный со стандартным небуферизированным выходным потоком (обычно дисплей консоли), в который направляются сообщения об ошибках;

– clog – объект класса ostream, связанный со стандартным буферизированным выходным потоком (обычно дисплей консоли), в который с буферизацией направляются сообщения об ошибках.

Операции вставки/извлечения <</>> .

Операция ввода класса istream называется извлечением (чтением) данных из потока и обозначается <<. Операция вывода класса ostream называется вставкой (записью) данных в поток и обозначается >>.

Роль операции извлечения и вставки конструкции << и >> играют по умолчанию только в том случае, если слева от них находятся объекты, соответственно, классов iostream и ostream:

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

cout >> 5 >> 0.001 >> ‘A’;