Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programmirovanie.docx
Скачиваний:
0
Добавлен:
26.12.2019
Размер:
373.72 Кб
Скачать

1. Принципы объектно-ориентированного программирования. Основными свойствами ооп являются:

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

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

class < имя> { [private: ] < описание скрытых элементов > public: < описание доступных элементов > };

Метки private и public называются спецификаторами доступа. Любые поля и методы, объявленные после спецификатора public доступны при любом обращении программы к объектам класса. Поля и методы , объявленные после спецификатора private доступны только методам данного класса. class monstr { int health, ammo; public: monstr (int he = 100, int am = 10){ health = he; ammo = am; } void draw (int x,int y, int scale, int position); int get_health () {return health;} int get_health () {return ammo;} };

В этом классе 2 скрытых поля - health и ammo, получить значения которых извне можно с помощью методов get_health() и get_ammo().

void monstr::draw(int x,int y, int scale, int position){ /* тело метода */ }

3. Понятие объекта. Конкретные представители класса называются экземплярами класса или объектами.

mostr vasia; //Объект класса monstr с параметрами по умолчанию monstr Super(200,300); //Объект с явной инициализацией mostr stado[100] // Массив объектов с параметрами по умолчанию

monstr *beavis = new monstr (10): // Динамический объект // (второй параметр задается по умолчанию)

monstr &butthead = Vasia: // Ссылка на объект

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

class monstr { ... int get_health() const {return health;} }; const monstr Dead (0,0); // Константный объект cout <<Dead.get_health();

Константный метод объявляется с ключевым словом const после списка параметров. Он не может изменять значение полей класса. Может вызывать только константные методы и может вызываться для любых объектов. Указатель this. Каждый объект содержит свой экземпляр полей класса. Методы класса находятся в классе в единственном экземпляре и используется всеми объектами совместно. Поэтому необходимо обеспечить работу метода с полями, именно того объекта для которого они были вызваны. Это обеспечивается передачей функции скрытого параметра this в котором храниться константный указатель на вызвавший функцию объект. Указатель this не явно используется внутри метода для ссылок на элементы объекта. В явном виде он применяется для возвращения из метода указателя на вызвавший объект. Указатели this можно также применять для идентификации поля класса в том случае, когда его имя совпадает с именем формального параметра

4. Конструкторы. Конструктор предназначен для инициализации объекта и вызывается автоматически при его создании. Свойства конструктора : 1) Конструктор не возвращает значение, даже типа void. Нельзя получить указатель конструктора. 2) Класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации. 3) Конструктор, вызываемый без параметров, называется конструктором по умолчанию. 4) Параметры конструктора могут иметь любой тип кроме этого же класса. 5) Если программист не указал не одного конструктора, компилятор создает его автоматически. 6) Конструкторы не наследуются. 7) Конструктор нельзя описать с модификаторами: const, virtual и static.

Конструктор вызывается, если в программе встречается одна из следующих записей: имя_класса имя_объекта [(список параметров)]; // список параметров не должен быть пустым имя _класса (список параметров); // создается объект без имени( список может быть пустым ) имя_класса имя_объекта = выражение; // создается объект без имени и копируется

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

имя_класса::имя_класса (const имя_класса&объект) { //тело конструктора копирования }

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

5. Деструкторы. Это особый вид метода, применяющийся для освобождения памяти, занимаемой объекта. Деструктор вызывается автоматически, когда объект выходит из области видимости.

Имя деструктора начинается с тильды(~), непосредственно за которой следует имя класса. Деструктор: *не имеет аргументов и возвращаемого значения; *не может быть объявлен как const или static; *не наследуется;

Если деструктор явным образом не определен компилятор создает пустой деструктор. Описывать в классе деструктор явным образом требуется, когда объект содержит указатели на память выделяемую динамически. Иначе при уничтожении объекта память на которую ссылались его поля указатели не будет помечена как свободная. Для нашего класса monstr деструктор может быть описан следующим образом. monstr::~monstr() {delete[] name;}

monstr*m;... m->~monstr();

6. Статические элементы класса. static

Статические поля - применяются для хранения данных общих для всех объектов класса.

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

class A{ public: static int count: // Объявление в классе }; ... int A::count; // Определение в глобальной области. По умолчанию инициализируется нулем. // int A::count = 10; Пример инициализации произвольным значением

* статически поля доступны как через имя класса, так и через имя объекта

A *a,b; cout <<A::count<<a-> count<< b.count; // будет выведено одно и то же

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

class A{ static int count; // Поле count скрытое public: static void inc_count(){ count++;} }; A::int count: // Определение в глобальной области void f() { A a; // a,count++ - нельзя, поле count скрытое // Изменение моля с помощью статического метода: a.inc_count(); // или A::inc_count(): }

7. Дружественные функции и классы. Иногда необходимо иметь непосредственный доступ извне к скрытым полям класса. Для этого служат дружественные функции и дружественные классы. Если все методы какого-либо класса должны иметь доступ к скрытым полям другого, то весь класс объявляется дружественным с помощью ключевого слова friend.

Дружественный класс.

class hero{ friend class mistress; } class mistress{ void f1(); void f2(); }

Дружественная функция. Применяется для доступы к скрытым полям класса и представляет собой альтернативу метода. Метод, как правило, используется при реализации свойств объекта, а в виде дружественных функций оформляются действия не представляющие свойства класса.

Пример:

class monstr; // Предварительное объявление класса class hero{ public: void kill (monstr &); ... }; class monstr{

...

friend void hero::kill(monstr&); // класс hero должен быть определен ранее }; int steal_ammo(monstr&M){ return M.ammp; } void hero::kill(monstr&M){ M.health=0; M.ammo=0; }

8. Перегрузка операций. Функция - операция содержит ключевое слово Operator, за которым следует знак переопределяемой операции: тип operator операция (список параметров) { тело функции }

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

Правила перегрузки операций:

* при перегрузке сохраняется кол-во аргументов, приоритеты операций и правила ассоциаций, используемые стандартный тип данных; * для стандартных типов данных переопределять операции нельзя; *перегруженные операторы не могу иметь аргументов по умолчанию; * перегруженные операции наследуются, за исключением знака присваивания; * перегруженные операции не могу определяться как static;

Перегрузка унарных операторов & * + - ~ !

Так, унарный оператор "минус" для комплексных чисел может быть определен внутри класса так: const complex operator - () { return complex (-Re, -Im); }

class complex {... friend const complex operator - (const complex& C);... }

const complex operator - (const complex& C) { return complex (-C.Re,-C.Im); } Перегрузка бинарных оператор +; -; *; /; %; == ; <=; >= ;!= ; && ; || ; << ; >>

Рассмотрим перегрузку операторов сложения для комплексных чисел: const complex operator + (complex C){ complex C1(*this); C1.Re = C1.Re+C.Re; C1.Im = C1.Im + C.Im; return C1; }; const complex operator + (double D) { complex C1(*this); C1.Re = C1.Re+D; return C1; };

Перегрузка оператора индексирования

const double operator [] (const int &i) { if (i=1) return Re; if (i=2) return Im; return 0; }

9. Наследование. Множественное наследование. Наследование. Механизм наследования классов позволяет строить иерархии в которых производные классы получают элементы базовых классов и могут дополнять или изменять их свойства.

class имя : [private | protected | public] базовый_класс { тело класса };

Правила наследование в С++ можно записывать следующим образом:

* в производном классе можно добавлять свои поля - члены класса;

* в производном классе можно добавлять свои методы - члены класса;

* в производном классе можно переопределять методы базового класса (сохраняя точное совпадение с исходным прототипом, то есть количество типы аргументов и возвращаемый тип). Исключение: если возвращаемый тип является указателем или ссылкой на базовый класс, он может быть замене указателем или ссылкой не порождаемый класс;

* конструкторы не наследуются, поэтому производный класс должен иметь собственные конструкторы. Если в конструкторе производного класса, явный вызов конструктора базового класса, отсутствует, то вызывается конструктор базового класса по умолчанию;

* для иерархии состоящей из нескольких уровней конструкторы базовых классов вызываются, начиная с самого верхнего уровня;

* деструкторы не наследуются. Если программист не описал в производном классе деструктор он формируется по умолчанию и вызывает деструкторы всех базовых классов;

* в отличие от конструкторов при описании деструктора производного класса в нем не требуется явно вызывать деструкторы базовых классов т.к. это будет сделано автоматически ;

* для иерархии классов состоящей из нескольких уровней деструкторы вызываются в порядке строго обратном вызову конструктора: сначала деструктор производного класса потом базового Множественное наследование. Означает, что класс имеет несколько базовых классов. Если в базовых классах есть одноименные элементы может произойти конфликт идентификаторов , который устраняется с помощью операторов доступа к области видимости. Множественное наследование применяется для того, чтобы обеспечить производные класс свойствами двух или более базовых. Чаще всего один из этих классов является основным, а другие обеспечивают некоторые дополнительные свойства, поэтому их называют классами подмешивания. Рекомендуются эти класса создавать виртуальными с помощью конструктора без параметров.

10. Виртуальные функции. Виртуальная функция, эта функция объявленная с ключевым словом virtual и переопределенная в одном или нескольких производных классах. Виртуальные функции являются особыми, потому что при вызове объектов производного класса с помощью указателя С++ определяет во время выполнения программы какую функцию вызвать. Для разных объектов вызываются различные версии одной и той же виртуальной функции

virtual void draw(int x, int y, int scale, int position);

Если в базовом классе, метод определен как виртуальный, то метод определенный в производном классе с тем же именем и набором параметров становиться виртуальным, а с отличающимся набором - обычным. Виртуальные методы наследуются. Если в классе вводится описание виртуального метода он должен быть определен хотя бы как чистый виртуальный. Чисто виртуальный метод содержит признак = 0 вместо тела, например: virtual void f(int)=0; Если определить метод draw как виртуальный, то решение о том метод какого класса вызвать будет применяться на этапе выполнения программы. monstr *r,*p; r=new monstr; // создается объект класса monstr p=new daemon; // создается объект класса daemon r->draw(1,1,1,1); // вызывается метод monstr::draw p->draw(1,1,1,1) // вызывается метод daemon::draw

11. Раннее и позднее связывание. Ранее связывание означает, что объект и вызов функции связываются между собой на этапе компиляции - это означает, что всякая необходимая информация для того, чтобы определить какая именно функция будет вызванной известно на этапе компиляции программы. В С++ также реализован механизм позднего связывания. Когда разрешения ссылок на метод происходит на этапе выполнения программы. Этот механизм реализован с помощью виртуальных функций. Для каждого класса содержащего хотя бы один виртуальный метод, компилятор создает таблицу виртуальных методов, которой для каждого виртуального метода записан его адрес в памяти. Адрес любого виртуального метода содержит в этой таблице одно и тоже смещение для каждого класса. В каждом классе существует дополнительное поле ссылки на таблицу виртуальных методов. На этапе компиляции ссылки на виртуальные методы заменяются на обращения таблицы виртуальных методов через поле ссылки. А на этапе выполнения программы выбирается метод из таблицы. Таким образом вызов виртуального метода в отличии от обычных методов выполняются через дополнительный этап, получения адреса метода из таблицы, что несколько заменяет выполнения программы. Виртуальный механизм работает только при использовании указателей или ссылок на объекты. Объект определенный через указатель или ссылку и содержащий виртуальные методы называется полиморфным. Полиморфизм состоит в том, что с помощью одного и того же обращения к методу выполняются различные действия в зависимости от типа на который ссылается указатель.

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

#include <iostream> using namespace std; class Point // объявление абстрактного класса { public: Point() {} // конструктор ~Point() {} // деструктор virtual void Point()=0; // чистая виртуальная функция void main() { Point* P //P=new Point(); // !!!!!нельзя создать объект абстрактного класса // P->Print(); P=new Point1(1); P->Print(); // 1 P=new Point2(2,3); P->Print(); // 2 3 Абстрактный класс может использоваться только в качестве базового для других классов. Объекты абстрактного класса создавать нельзя. Абстрактный класс нельзя использовать при явном приведении типов, для описания типа параметра и типа возвращаемого функции значения. Допускается объявлять указатели и ссылки на абстрактный класс, если при инициализации не требуется создавать объект. Если класс производный от абстрактного не определяет все чисто виртуальные функции, то этот класс тоже является абстрактным.

13. Библиотека классов ввода/вывода С++. Потоки Поток - это абстрактное понятие, относящиеся к любому переносу данных от источника к приемнику. Чтение данных из потока называется извлечением, вывод в поток, помещением или включением. Обмен с потоком для увеличения скорости передачи данных производится через специальную область оперативной памяти - буфер. Передача данных выполняется при выводе после заполнения буфера, а при вводе, если буфер исчерпан. Потоки по направлению можно разделить на выходные (данные вводятся в память), выходные (данные выводятся из памяти) и двунаправленные (допускающие как включение, так и выключение). В С++ существует несколько предопределенных потоков, открывающие автоматически вместе с началом выполнения программы.

Объект

Класс

Описание

cin

istream

Связывается с клавиатурой (стандартным буферизованным вводом)

cout

ostream

Связывается с экраном (стандартным буферизованным выводом)

cerr

ostream

Связывается с экраном (стандартным не буферизованным выводом), куда направляются сообщения об ошибках

clog

ostream

Связывается с экраном (стандартным буферизованным выводом), куда направляются сообщения об ошибках

14. Потоковые классы. Для поддержки потоков библиотека С++ содержит иерархию классов, построенную на двух базовых: ios и streambuf. От этих классов наследуется класс istream для выходных потоков и ostream - для выходных. Два последних класса являются базовыми для класса iostream, реализующего двунаправленные потоки. ios - базовый класс потоков; istream - класс входных потков; ostream - класс выходных потоков; iostream - класс двунаправленных потоков; istringstream - класс входных строковых потоков; ostringstream - класс выходных строковых потоков; stringstram - класс двунаправленных строковых потоков: ifstream - класс входных файловых потоков; ofstream - класс выходных файловых потоков; fstream - класс двунаправленных файловых потоков

15. Создание собственных операторов извлечения и вставки. << называют оператором вставки (insertion) >> называется оператором извлечения (extraction)

Создание операторов вставки

class three_d { public: int x,y,z; // трехмерные коородинаты three_d (int a, int b, int c) { x=a; y=b; z=c; } }; // (оператор вставки для three_d) ostream &operator<< (ostream &stream, three_d obj) { stream << obj.x <<", "; stream<< obj.y << ", "; stream<< obj.z <<"\n"; return stream; // возврат потока }

int main() { three_d a(1,2,3), b(3,4,5), c(5,6,7); cout <<a << b << c ; system ("pause"); return 0; }

Общая форма функции вставки имеет вид: ostream &operator<<(ostream &поток, тип_класса объект) { // характерный для типа код return stream; //возврат потока } В приведенном примере перегруженная функция вставки не является членом класса. Причина заключается в том, что, если функция оператор является членом класса, то левым операндом служит объект того класса, которая осуществляет вызов. В нашем случае левым аргументом является поток. Поэтому для того, чтобы получить доступ к скрытым полям класса и не нарушать принцип объектно-ориентированного программирования - инкапсуляция , необходимо оператор вставки сделать дружественным классом. Перегрузка операторов извлечения

// получение трехмерных значений - экстрактор istream &operator>>(istream &stream, three_d &obj) { stream >> obj.x >> obj.y >> obj.z; return stream; }

Общая форма экстрактора имеет вид: istream &operator >> (istream &поток, тип_класса &объект) { // код экстрактора return stream; }

16. Форматирование ввода/вывода. Форматирование с помощью функций-членов класса ios. Форматирование задается битовыми флажками. Управление флажками возможно следующими методами: mtflags flags() const - возвращает флаги форматирования для ввода и вывода; fmtflags flags(fmtflags fmtfl) - устанавливает новый набор флагов и возвращает предыдущий; fmtflags setf(fmtflags fmtfl) - устанавливает новый набор флагов и возвращает предыдущий; fmtflags setf(fmtflags fmtfl, fmtflags mask) - устанавливает fmtfl & mask и возвращает предыдущий набор флагов;

Небольшой пример ввода числа и последующего вывода его в десятиченой и шестнадцатричной системе.Для завершения необходимо ввести число 0

#include <iostream>

using namespace std;

int main(){

int k=1;

cout << "Input zero for close\\n";

while(k){

cout<<"input number: ";

cin>>k;

cout<<"dec: "<<k<<hex<<", hex: "<<k<<dec<<endl;}

return 0;} (значение всех флажков №17)

Доступ к потокам на основе массивов может быть также осуществлен с помощью стандартных функций-членов класса ios, таких как get() и put(). Также можно использовать функцию еоf() для того, чтобы определить, когда будет достигнут конец массива. Например, следующая программа показывает, как прочитать содержание массива с использованием функции get(): #include <iostream.h> #include <strstrea.h> int main() { char s[] = "This is a test array\23\22\21\a\t\n"; istrstream ins(s); char ch; // читает содержимое массива любого типа while ( !ins.eof ()) { ins.get (ch); cout << ch;} return 0;} Если необходимо прочесть данные из буфера, то можно использовать функцию-член read(). Для записи данных в буфер используется функция write().

17. Форматирование ввода/вывода(№16). Манипуляторы Значения флажков задаются следующим вложенным типом: enum fmt_flags { // различные флаги

boolalpha = 0x0001, // ввод/вывод булева типа в символьном виде

dec = 0x0002, // вывод/ввод целых в десятичном виде

fixed = 0x0004, // вывод в плавающей точкой в fixed-point нотации

hex = 0x0008, // вывод/ввод целых в шестнадцатиричном виде

internal = 0x0010,

left = 0x0020, // добавляет символы справа при выводе

oct = 0x0040, // вывод/ввод целых в восмиричном виде

right = 0x0080, // добавляет символы слева при выводе

scientific = 0x0100, // вывод плавающей точке в научной нотации

showbase = 0x0200, // отображает префикс основания

// при выводе целых чисел

showpoint = 0x0400,

showpos = 0x0800, // отображает + при выводе

skipws = 0x1000, // пропускает начальные пробелы при вводе

unitbuf = 0x2000, // сбрасывает вывод после каждой операции вывода

uppercase = 0x4000, // вывод в верхнем регистре

adjustfield = left | right | internal, // добавляет символы слева и справа

basefield = dec | oct | hex,

floatfield = scientific | fixed }; Манипулятор:

>>>>>>>>>>>>>>>>setfill - точка<<<<<<<<<<<<<<<<<<

Пример

#include <iostream.h> #include <iomanip.h> int main { double d[] = {1.234, -12.34567, 123.456789, -1.234, 0.00001}; coud << setfill (',') <<setprecision(4) <<setiosflags (ios::showpoint |ios::fixed); for (int i = 0; i<5;i++) cout <<setw(12) <<d[i] <<endl; system ("pause"); return 0; }

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]