
- •Принципы ооп:
- •Ооп, как средство обеспечения требований предъявляемых к современному программному обеспечению
- •Причины использования перегрузки функций
- •Конструкторы и деструкторы производных классов.
- •Полиморфизм и виртуальные функции, раннее и позднее связывание.
- •Форматирование данных, флаги и манипуляторы потоков.
- •Пример форматирования
- •Манипуляторы без параметров:
- •Int I, // параметр обычного типа
Конструкторы и деструкторы производных классов.
Допустим, у нас есть три класса: базовый класс 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’;