Объектно-ориентированное программирование

История развития C++ для операционных систем. Его графика и пользовательские интерфейсы. Объектно-ориентированное программирование. Бинарные и унарные операторы. Правила определения операторных функций. Использование языка UML и диаграммы классов.

Рубрика Программирование, компьютеры и кибернетика
Вид реферат
Язык русский
Дата добавления 24.09.2017
Размер файла 73,7 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

private:

int *_p;

};

...

};

Функции-члены класса Matrix, возвращающие граничные значения для данного итератора:

reverse_iterator rbegin()const{return m+size()-1;}

reverse_iterator rend()const{return m-1;}

Теперь перебор в обратном порядке выглядит так:

for(Matrix::reverse_iterator r=m.rbegin();r!=m.rend();++r)

*r=rand();

Недостатки приведенной концепции: необходимо определять по две дополнительные функции-члены контейнера (begin,end) для каждого типа итератора.

Другая идиома для итератора, не имеющая этих недостатков:

class m_iter{

public:

m_iter(Matrix& m):_begin(m.m),_end(m.m+m.size()){}

void First(){_p=_begin;}

bool NotDone()const{return _p!=_end;}

int& CurrentItem()const{return *_p;}

void Next(){++_p;}

private:

int *_begin, *_end, *_p;

};

Использование:

m_iter mi(m);

for(mi.First();mi.NotDone();mi.Next())

mi.CurrentItem()=rand();

Однако класс такого итератора должен иметь доступ к представлению контейнера, поэтому его нужно сделать другом контейнера:

class Matrix{

...

friend class m_iter;

};

Дружественные функции

Ключевое слово friend (друг) служит спецификатором, уточняющим свойства функции. Оно дает функции-не-члену доступ к скрытым членам класса и предоставляет способ для обхода ограничений сокрытия данных в C++. Однако должна быть веская причина для обхода этих ограничений, поскольку они важны для надежного программирования.

Одна из таких причин состоит в том, что некоторые функции нуждаются в привилегированном доступе более чем к одному классу. Например, нам нужно определить оператор, который умножает матрицу Matrix на вектор Vector. Представление Matrix и Vector скрыто (private:)

class Matrix;

class Vector{

float v[4];

//...

friend Vector operator*(const Matrix&,const Vector&);

};

class Matrix{

Vector v[4];

//...

friend Vector operator*(const Matrix&,const Vector&);

};

Vector operator*(const Matrix& m,const Vector& v)

{

Vector r;

for(int i=0;i<4;i++){

r.v[i]=0;

for(int j=0;j<4;j++)r.v[i]+=m.v[i].v[j]*v.v[j];

}

return r;

}

Наследование

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

Многие полезные типы являются вариантами других, и часто бывает утомительно создавать для каждого из них один и тот же код. Производный класс наследует описание базового класса; затем он может быть изменен добавлением новых членов, изменением существующих функций-членов и изменением прав доступа. Эта концепция полезна так же, как полезна таксономическая классификация: и слон и мышь являются млекопитающими. Информация о том, что млекопитающие - теплокровные высшие позвоночные, подробно изложена лишь однажды - в базовом понятии. В понятиях «слон» и «мышь» даются лишь характерные особенности этих животных.

Производный класс

Класс можно сделать производным от существующего с использованием следующей формы:

class имя_класса: (public|protected|private)opt имя_базового_класса

{

объявления членов

};

Ключевое слово class как всегда можно заменить словом struct, если подразумевается, что все члены открыты.

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

Рассмотрим пример:

<сначала - только члены данных>

<потом - функции-члены>

<потом - конструкторы>

//inheritance.h

class employee

{

public:

employee (char *name, double salary);

void print()const;

private:

char nm[30];

double slry;

};

enum language {ASSEMBLER,BASIC,PASCAL,C,CPP,SMALLTALK};

class programmer1

{

public:

programmer1(char *name, double salary, language lang);

void print()const;

private:

char nm[30];

double slry;

language lng;

};

class programmer2:public employee

{

public:

programmer2(char *name, double salary, language lang);

void print()const;

private:

language lng;

};

//inheritance.cpp

#include "inheritance.h"

employee::employee(char *name, double salary)

:slry(salary)

{

strcpy(nm,name);

}

void employee::print()const

{

cout<<endl<<"Name: "<<nm<<", Salary: "<<slry<<"$";

}

programmer1::programmer1(char *name, double salary, language lang)

:slry(salary),lng(lang)

{

strcpy(nm,name);

}

void programmer1::print()const

{

cout<<endl<<"Name: "<<nm<<", Salary: "<<slry<<"$, Language:";

switch(lng){

case C:cout<<"C";break;

case CPP:cout<<"C++";break;

default:cout<<"Another language";break;

}

}

programmer2::programmer2(char *name, double salary, language lang)

:employee(name,salary),lng(lang)

{}

void programmer2::print()const

{

employee::print();//печать информации о работнике

// должен использоваться оператор::, потому что

// print() была замещена в programmer2

// ошибка:

// cout<<endl<<"Name: "<<nm<<", Salary: "<<slry<<"$, Language:";

// нельзя обратиться к закрытым членам базового класса

cout<<", Language:";//печать информации, относящейся

switch(lng){ // только к программисту

case C:cout<<"C";break;

case CPP:cout<<"C++";break;

default:cout<<"Another language";break;

}

}

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

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

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

employee e1("John",80),e2("Ben",90);

v.print();p.print();

programmer1 p1("Ron",200,BASIC);

p1.print();

programmer2 p2("Michael",500,C);

p2.print();

Как видите, использование классов programmer1 (без наследования) и programmer2 (с наследованием) здесь не отличается. Однако наследование имеет преимущество. Определение класса programmer2 как производного от employee делает его подтипом employee. Это значит, что объектом programmer2 можно пользоваться везде, где допустим employee. Например:

print_in_report(const employee& e){ e.print(); }

print_in_report(e1);

//print_in_report(p1); //error

print_in_report(p2); //OK

Копирование и срезка

employee arr_emp[3]={e1,p2,e2};

mas[0]=v;

// mas[0]=p1;//error

for(int i=0;i<3;++i)mas[i].print();

programmer2 p;

employee r=p;//срезка

Копируется только employee-часть programmer2. Этот эффект называют срезкой. Часто он является нежелательным. Одной из причин использования указателей и ссылок на объекты в иерархии является желание избежать срезки. Например:

employee *rptr=&r;//адрес работника

rptr=&p;//адрес программиста. Срезка отсутствует

Производные классы (Derived* можно использовать как Base*)

Функции-члены (замещение, обращение к ф-членам базового кл.)

Конструкторы и деструкторы (инициализация членов базового класса через конструктор базового класса)

UML

UML расшифровывается как Unified Modeling Language - унифицированный язык моделирования. Он является визуальным языком и предназначен для создания моделей программ. Под моделями программ понимается графическое представление программ в виде различных диаграмм, отражающих связи между объектами в программном коде.

Виды диаграмм:

1. Диаграммы прецедентов

2. Диаграммы видов деятельности

3. Диаграммы взаимодействий (подвид - диаграмма последовательностей)

4. Диаграммы классов

5. Диаграммы состояний

6. Диаграммы развертывания

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

Для чего используется язык UML

Прежде всего UML - язык общения с самим собой, членами команды и клиентами.

Если возникает необходимость обсудить проект и объяснить другим людям структуру классов, механизм взаимодействия объектов, причем без использования языка, подобного UML, то разговор получится путанным и бесконечным. Язык UML предлагает не только оптимальный путь написания проектов, созданных с применением объектных технологий, но также вынуждает разработчика более четко формулировать используемые им принципы (поскольку их нужно изложить в письменном виде).

Диаграмма классов

Описывает классы и отражает отношения, существующие между ними.

Класс обозначается прямоугольником, содержащим до трех элементов:

· Имя класса

· Имена методов (функций) класса

· Имена данных-членов класса

Модификаторы доступа обозначаются знаками + public, # protected, - private.

Возможны следующие типы отношений между классами.

· Отношение “is-a” - в этом случае один класс является подвидом другого класса

· Отношение “has-a” - когда один объект одного класса «содержит» объект другого класса в качестве элемента данных.

Кардинальность (или кратность) элементов отношения показывают количество включаемых объектов.

Иерархия классов

Базовый класс (employee) может иметь несколько производных классов (teacher, manager, …):

class teacher: public employee{…};

class manager: public employee{…};

Производный класс (teacher), в свою очередь, сам может быть базовым классом (для english_teacher):

class english_teacher: public teacher{…};

Такой набор связанных классов называется иерархией классов. Иерархия имеет вид дерева (если не использовать множественное наследование).

Преимущества использования производных классов:

Код используется повторно. Тип programmer2 использует существующий, хорошо проверенный код из employee;

Иерархия отражает взаимоотношения, свойственные проблемной области;

Различные полиморфные механизмы позволяют клиентскому коду рассматривать programmer2 в качестве подтипа employee, что упростит клиентский код.

Преобразование типов

Указатель на производный класс может быть преобразован в указатель на базовый класс. У нас есть объект programmer2:

employee r("Vasya",80),*pr;

pr=&r;

pr->print();//employee::print

programmer2 p("Alex",300,CPP), *pp;

pr=pp=&p;//преобразование

pp->print();//programmer2::print

pr->print();//employee::print

Тот факт, что указатель теперь указывает на объект p типа programmer2, в данном случае в расчет не принимается.

Поля типа

Для того, чтобы через указатель на базовый класс вызывать подходящие функции (programmer2::print или employee::print), мы должны решить, какому типу на самом деле принадлежит объект, на который указывает указатель?

Для этого мы можем ввести в базовый класс поле типа, чтобы заинтересованные функции могли его проверить:

class employee{

public:

enum Rab_type{R,P};

Rab_type type;

employee():type(R){}

void print()const;

};

class programmer:public employee{

public:

programmer(){type=P;}

void print()const;

};

void employee::print()const{

cout<<"employee::print"<<endl;

}

void programmer::print()const{

cout<<"programmer::print"<<endl;

}

void print(employee* pr){

switch(pr->type){

case employee::R:

pr->print();

break;

case employee::P:

const programmer* p=static_cast<const programmer*>(pr);

p->print();

break;

}

}

Добавление нового производного от employee класса подразумевает внесение изменений во все ключевые функции системы:

в базовом классе employee в перечислимый тип добавляется новая константа;

пишется производный класс (аналогично programmer);

в функцию ::print добавляется новая ветвь.

Виртуальные функции

Виртуальные функции решают проблему, связанную с полем типа. Для того, чтобы сделать функцию виртуальной, нужно поставить ключевое слово virtual слева от объявления функции в классе. Например:

class employee_v{

public:

virtual void print()const;

};

При этом определение виртуальной функции синтаксически такое же, как и у обычной невиртуальной функции-члена:

void employee_v::print()const{

cout<<"employee_v::print"<<endl;

}

Виртуальная функция замещается в производном классе:

class programmer_v:public employee_v{

public:

virtual void print()const;

};

void programmer_v::print()const{

cout<<"programmer_v::print"<<endl;

}

Вызов виртуальной функции синтаксически такой же, как и обычной функции:

employee_v r1;

programmer_v p1;

r1.print();//employee_v::print

p1.print();//programmer_v::print

В этих двух случаях вызовутся функции print соответствующих классов. Так было бы и в случае невиртуальных функций print (т.е. без ключевого слова virtual).

void print_v(employee_v* pr){

pr->print();//employee_v::print или programmer_v::print

}

В этом случае мы вызываем функцию-член (print) по указателю pr на employee_v. В случае, если бы функция-член print была объявлена невиртуальной, то однозначно вызвалась бы функция employee_v::print (что определяется типом указателя). Однако, так как функция print виртуальна, вызывается либо employee_v::print, либо programmer_v::print, в зависимости от того, указывает pr на объект типа employee_v либо на объект типа programmer_v. Например:

employee_v r1,r2;

programmer_v p1,p2;

print_v(&r1);// employee_v::print

print_v(&p1);// programmer_v::print

Теперь мы можем запомнить указатели на различные объекты в массиве и вызвать print_v в цикле:

employee_v *record[4]={&r1,&p1,&r2,&p2};

for(int i=0;i<4;++i){

print_v(record[i]);

}

Вызовутся функции в таком порядке: employee_v::print, programmer_v::print, employee_v::print, programmer_v::print.

Так как наша функция print_v выродилась в единственный вызов функции-члена print, мы можем написать непосредственно

for(int i=0;i<4;++i){

record[i]->print();

}

В случае, если мы используем виртуальные функции, добавление нового производного от employee класса не требует изменений ни в базовом классе, ни в коде, использующем виртуальные функции (в нашем случае этот код - приведенный выше цикл). Заметьте, что это будет работать, даже если указанный цикл был написан и откомпилирован до того, как производный класс programmer_v::print был вообще задуман! Данный факт служит краеугольным камнем объектно-ориентированных проектов и придает стабильность развивающейся программе.

Полиморфизм

Когда функции базового класса (employee_v) ведут себя «правильно» независимо от того, какой конкретно производный класс используется, это называется полиморфизмом. Тип, имеющий виртуальные функции, называется полиморфным типом. Для достижения полиморфного поведения в C++ вызываемые функции-члены должны быть виртуальными, и доступ к объекту должен осуществляться через ссылки или указатели. При непосредственных манипуляциях с объектом (без помощи указателя или ссылки) его точный тип известен компилятору, и поэтому полиморфизм времени выполнения не требуется.

Абстрактные классы

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

class figure{

public:

void move_to(int x, int y){_x=x; _y=y;}

virtual void draw(HDC);

virtual void rotate(double);//angle measured in degrees

protected:

figure(int x,int y):_x(x),_y(y){}

int _x,_y;

};

Производные от figure классы переопределяют виртуальные функции и добавляют специфические члены данных.

class circle:public figure{

public:

circle(int x,int y,int r)

:figure(x,y),_r(r){}

virtual void draw(HDC);

virtual void rotate(double){};

private:

int _r;

};

class line:public figure{

public:

line(int x0, int y0,

int x1, int y1)

:figure(x0,y0),_dx(x1-x0),_dy(y1-y0)

{}

virtual void draw(HDC);

void rotate(double);

private:

int _dx,_dy;

};

Для figure невозможно разумно определить виртуальные функции:

void figure::draw(HDC){

assert(false);//этот код не должен быть вызван

}

void figure::rotate(double){

assert(false);//этот код не должен быть вызван

}

Попытка создания фигуры допустима, но неразумна:

figure f1(200,200);//фигура с центром, но без формы

circle c1(100,100,10);

line l1(120,100,130,105);

figure* mas[2]={&c1,&l1};

for(int i=0;i<2;++i){

mas[i]->draw(hdc);

mas[i]->move_to(100,110);

mas[i]->draw(hdc);

mas[i]->move_to(100,140);

mas[i]->rotate(40);

mas[i]->draw(hdc); }

Включение

Виды включения: композиция и агрегация.

Шаблоны

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

Допустим у нас есть класс stack3, который реализует концепцию стека символов (char).

class stack3

{

public:

stack3();

void push(char c);

char pop();

bool is_empty()const;

bool is_full()const;

private:

enum{ max_len=100};

int top;

char s[max_len];

};

Функции реализованы следующим образом:

stack3::stack3():top(0){}

void stack3::push(char c){

assert(top<max_len);

s[top++]=c;

}

char stack3::pop(){

assert(top>0);

return s[--top];

}

bool stack3::is_empty()const {return top==0;}

bool stack3::is_full()const {return top==max_len;}

Мы можем использовать объекты этого класса следующим образом:

stack3 reverse_order(stack3 s){

stack3 tmp;

while(!s.is_empty()){

tmp.push(s.pop());

}

return tmp;

}

Пример шаблона класса:

template <class T> class stack4

{

public:

stack4(); //конструктор

void push(T c);

T pop();

bool is_empty()const;

bool is_full()const;

private:

enum{ max_len=100};

int top;

T s[max_len];

};

template<class T>stack4<T>::stack4():top(0){}

template<class T>void stack4<T>::push(T c){

assert(top<max_len);

s[top++]=c;

}

template<class T>T stack4<T>::pop(){

assert(top>0);

return s[--top];

}

template<class T>bool stack4<T>::is_empty()const {return top==0;}

template<class T>bool stack4<T>::is_full()const

{return top==max_len;}

Префикс template <class T> указывает, что объявлен шаблон (template), и что в объявлении на месте T будет указан фактический тип. T - имя типа, а не обязательно класса.

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

stack4<char> sc;

stack4<int> si;

stack4<char*> sd;

Без использования шаблонов для реализации этого примера пришлось бы писать три определения классов, а с использованием шаблона - только одно определение шаблона.

Функция, работающая со стеком stack4<double>:

stack4<double> reverse_order(stack4<double> s){

stack4<double> tmp;

while(!s.is_empty()){

tmp.push(s.pop());

}

return tmp;

}

Шаблон функции, работающий с любым стеком:

template <class STACK> STACK reverse_order(STACK s){

STACK tmp;

while(!s.is_empty()){

tmp.push(s.pop());

}

return tmp;

}

Исключение ненужных инстанцирований функций-членов

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

stack4<char> sc;//генерируется 5 функций

stack4<int> si1, si2;// генерируется 5 функций

//(количество создаваемых объектов не играет роли)

stack4<char> sd;//не генерируется новых функций, так как инстанцирование stack4<char> уже было выше

В нашем классе stack функции push и pop зависят от параметра шаблона, поэтому их генерирование необходимо. Так, функция push, сгенерированная для параметра char, работает не так, как функция push, сгенерированная для параметра int. В то же время функции is_empty и is_full от параметра шаблона не зависят. Функция is_empty для char абсолютно идентична функции is_empty для int. Для того, чтобы избежать генерирования лишних (полностью идентичных) функций, применяют следующий прием. Шаблонный класс создают производным от класса, не являющегося шаблоном. При этом в базовый класс помещают функции, не зависящие от параметра шаблона.

Применим данный прием для нашего стека:

class stack5_base

{

public:

stack5_base();

bool is_empty()const;

bool is_full()const;

protected:

enum{ max_len=100};

int top;

};

stack5_base::stack5_base()

:top(0)

{}

bool stack5_base::is_empty()const {return top==0;}

bool stack5_base::is_full()const {return top==max_len;}

template <class T> class stack5:public stack5_base

{

public:

void push(T c);

T pop();

private:

T s[max_len];

};

template<class T>void stack5<T>::push(T c){

assert(top<max_len);

s[top++]=c;

}

template<class T>T stack5<T>::pop(){

assert(top>0);

return s[--top];

}

Для нашего случая количество сгенерированных функций уменьшается до минимально необходимого:

//к этому моменту сгенерировано 3 функции для stack5_base

stack5<char> sc;//генерируются 2 функции

stack5<int> si1, si2;// генерируются 2 функции

//(количество создаваемых объектов не играет роли)

stack5<char> sd;//не генерируется новых функций, так как инстанцирование stack4<char> уже было выше

Шаблоны с параметрами-значениями

В шаблонах stack3 и stack4 для хранения элементов используется массив на 100 элементов. В некоторых случаях указанное значение избыточно, и память расходуется нерационально. В некоторых случаях этого количества недостаточно и тогда шаблоны stack3 и stack4 не подходят для решения задачи. Как же спроектировать шаблон так, чтобы при необходимости получить заданное количество элементов не нужно было писать новый шаблон? Это можно сделать (по крайней мере) двумя путями.

Первый (уже известный вам) - передавать количество необходимых элементов в конструктор и в конструкторе динамически выделять память (а в деструкторе освобождать). При этом затрачивается время на выделение/освобождение памяти.

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

class stack6_base

{

public:

stack6_base();

bool is_empty()const;

protected:

int top;

};

stack6_base::stack6_base()

:top(0)

{}

bool stack6_base::is_empty()const {return top==0;}

template <int N> class stack6_n:public stack6_base

{

public:

bool is_full()const;

};

template <int N> bool stack6_n<N>::is_full()const {return top==N;}

template <class T, int N> class stack6:public stack6_n<N>

{

public:

void push(T c);

T pop();

private:

T s[N];

};

template <class T, int N> void stack6<T,N>::push(T c){

assert(top<N);

s[top++]=c;

}

template <class T, int N> T stack6<T,N>::pop(){

assert(top>0);

return s[--top];

}

Инстанцирование шаблона выглядит следующим образом:

stack6<char,100> sc;//стек char на 100 элементов

stack6<int,10> si1, si2;//стек int на 10 элементов

stack6<char,5> sd;//стек char на 5 элементов

Следует заметить, что шаблон функции reverse_order, приведенный выше, будет работать также и с классами, сгенерированными по шаблону stack6:

reverse_order(sс);

Стандартная библиотека

Ни одна программа приличных размеров не пишется с использованием только «голых» конструкций языка. Обычно используются различные готовые библиотеки, в которых другие программисты уже написали код, облегчающий работу в данной предметной области. Существуют различные библиотеки для различных целей. Например, библиотека MFC используется для облегчения программирования для Win32 по сравнению с «чистым» программированием под Win32 API. Win32 API предполагает процедурный интерфейс к Windows, а MFC - объектно-ориентированный. Компания Borland предоставляет для тех же целей библиотеку OWL.

C Run-Time Library - предоставляет функции и макросы для многих аспектов программирования. Эта бибилиотека разрабатывалась достаточно давно, поэтому она ориентирована на использование в программах на языке C (как видно из ее названия). Так как C++ совместим с C, то C Run-Time Library можно использовать и в C++-программах. Функции этой бибилиотеки (в том виде, в котором она существует в Microsoft Visual С++) разбиты на 19 категорий, среди которых:

поддержка функций с переменной длиной списка аргументов;

выделение памяти (malloc, calloc и др.);

контроль жизненным циклом процесса (exec, exit);

операции с памятью (memcpy, …);

классификация символов (isalpha);

преобразование данных (atoi, _itoa, tolower);

отладка (_ASSERT, _CrtCheckMemory);

операции с каталогами (_chdir);

операции с файлами (_filelength);

математические функции и поддержка операций с плавающей точкой (sin, cos, abs, floor, ldexp(mant,exponent));

ввод-вывод

потоковый ввод-вывод (getc, fwrite)

низкоуровневый ввод-вывод (_open, _write)

ввод-вывод с/на консоль и из/в порт (_cprintf, _inp)

время и дата в стиле C (clock, difftime) <time.h>

алгоритмы поиска и сортировки (bsearch, qsort)

обработка ошибок в стиле С <errno.h>

функции над строками в стиле C (strcmp, strcpy) <string.h>, <stdlib.h>

Часть из этих функций стандартизирована ANSI и POSIX, часть - включена компанией Microsoft (все функции, начинающиеся с подчеркивания).

Существует также так называемая стандартная библиотека. Эта библиотека включена в стандарт C++.

Она предоставляет набор средств, которые можно классифицировать следующим образом:

Строки и потоки ввода-вывода;

Контейнеры (такие как vector, list и map) и алгоритмы, их использующие (сортировка, слияние, поиск и др.)

Поддержка численных расчетов (комплексные числа, вектора с арифметическими операциями и др.)

Стандартная библиотека C (поддержка операций с плавающей точкой, работа с C-строками и др.)

Поддержка средств языка времени выполнения (определение типа во время выполнения и др.)

Стандартная библиотека определена в пространстве имен std. Это сделано для того, чтобы избежать возможного конфликта между идентификаторами библиотеки и идентификаторами, определенными в программе. Поэтому нужно каждый идентификатор стандартной библиотеки предварять префиксом std::, либо перед их использованием написать using namespace std; (в последнем случае теряется преимущество от определения библиотеки в отдельном пространстве имен).

Каждое средство стандартной библиотеки становится доступным через какой-либо стандартный заголовочный файл наподобие <iostream>. Например, чтобы использовать строки, нужно подключить <string>, а для использования списков - <list>. Полный список заголовочных файлов дан в [Страуструп].

Ввод-вывод

Требуемый заголовочный файл - <iostream>.

Стандартный поток вывода - cin, ввода - cout. Ввод-вывод определен для всех встроенных типов. При выводе в поток с помощью операторов << и >> осуществляется два действия: преобразование значений в последовательность символов, и вывод этой последовательности символов с помощью низкоуровневых операций вывода.

void f(){

cout<<10<<13.7<<”abcd”;

double d; int i;

cin>>d>>i;

}

Здесь последовательность символов: 1,0,1,3,.,7,a,b,c,d.

Операторы << можно ставить в цепочки благодаря тому, что результат каждой операции является потоком.

Ввод осуществляется оператором >>. Тип операнда в его правой части определяет способ интерпретации символов и то, куда будут записываться полученные значения. Стандартный поток ввода - cin.

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

cout.put('s');

char ch;

cin.get(ch);

Форматирование.

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

cout<<123.4567;

cout.setf(ios_base::showpos);

cout<<123.4567<<setprecision(8)<<123.4567;

Строки

В ст. библ. имеется тип string, который дополняет строковые литералы, использовавшиеся ранее. Тип string обеспечивает множество полезных операций над строками, например, конкатенацию.

string s1="Hello",s2="world";

string s3=s1+", "+s2+'!';

cout<<s3;

Сложение (+) строк означает конкатенацию. Можно складывать строку со строкой, строковым литералом и символом. Оператор += добавляет что-либо в конец строки:

s3+='\n';

Строки могут сравниваться друг с другом и со строковыми литералами:

if(s1==s2){ }

if(s3=="Привет, мир!"){ }

Другие операции:

string s4=s3.substr(0,4);//взятие подстроки

s4.insert(0,"Road to ");//вставка

s4.replace(s4.find("Hell"),4,"Heaven");//поиск и замена

TextOut(hdc,1,1,s4.c_str(),s4.size());//преобразование в C-строку и число символов строки

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

Контейнеры

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

Вектор

Существуют

string

vector

list

ostream, istream, ofstream, ifstream, ostringstream.

Проектирование программ

Понятия - объекты - сообщения - атрибуты - классы - методы - общность (наследование).

Правила и рекомендации по написанию хороших программ применительно к конкретному языку.

Пример. Несколько рекомендаций для C++ из [5]:

· Везде, где только можно, используйте const.

· Для классов с динамическим выделением памяти объявляйте копирующий конструктор и оператор присваивания.

· Откладывайте определение переменных до последнего момента.

· Тщательно обдумывайте использование встраиваемых функций.

· Уменьшайте зависимости файлов при компиляции.

· Предпочитайте ошибки во время компиляции ошибкам во время выполнения.

В [5]приводятся обоснования, примеры использования и выгоды от пименения этих правил.

Паттерны проектирования. (Design Patterns)

Другой перевод - шаблоны проектирования (не путать с template).

Под паттернами проектирования понимается описание взаимодействия объектов и классов, адаптированных для решения общей задачи в конкретном контексте.

Пример. Концепция Document-View в MFC.

Document хранит представление, а View (Вид) определяет отображение документа на экране. Между документом и его видом в MFC установлен протокол взаимодействия «подписка/оповещение». Вид должен гарантировать, что внешнее представление отражает состояние документа. При каждом изменении внутренних данных документ оповещает все зависящие от него виды, в результате чего вид обновляет себя. Такой подход позволяет присоединить к одному документу несколько видов, обеспечив тем самым различные представления. Можно создать новый вид, не переписывая документ.

<Рисунок с док. и 3 видами: табл, гистограмма, круговая диаграмма >

Несколько паттернов из [6].

· Faзade (Фасад) Предоставление единого интерфейса для набора различных интерфейсов в системе.

· Adapter (Адаптер) Преобразование стандартного интерфейса класса в интерфейс, более подходящий для нужд клиента

· Итератор

Размещено на Allbest.ru

...

Подобные документы

  • Объектно-ориентированное программирование как методология программирования, опирающаяся на инкапсуляции, полиморфизме и наследовании. Общая форма класса. Наследование как процесс, посредством которого один объект получает свойства другого объекта.

    презентация [214,9 K], добавлен 26.10.2013

  • Приемы и правила объектно-ориентированного программирования с использованием языка С++. Общие принципы разработки объектно-ориентированных программ. Основные конструкции языка С++. Разработка различных программ для Windows с использованием WIN32 API.

    учебное пособие [1,6 M], добавлен 28.12.2013

  • Технологии программирования. Сущность объектно-ориентированного подхода к программированию. Назначение Си, исторические сведения. Алфавит, базовые типы и описание данных. Структуры и объединения. Операторы Си++. Функции. Библиотека времени выполнения.

    курс лекций [51,9 K], добавлен 03.10.2008

  • Создание программного обеспечения - системы имитационного моделирования на тему "Производственная линия с пунктами технического контроля". Описание входных и выходных данных. Объектно-ориентированное программирование. Диаграммы модулей и процессов.

    курсовая работа [1,2 M], добавлен 09.01.2014

  • Анализ объектно-ориентированного программирования, имитирующего способы выполнения предметов. Основные принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм. Понятие классов, полей, методов, сообщений, событий.

    контрольная работа [51,7 K], добавлен 22.01.2013

  • Использование скриптового языка программирования для разработки web-приложений (сценариев). Изучение основ объектно-ориентированного программирования в языке PHP. Ознакомление со специальными методами для работы с классами. Назначение интерфейсов.

    контрольная работа [25,1 K], добавлен 14.03.2015

  • Разработка программы с использованием принципов объектно-ориентированного программирования на языке высокого уровня С средствами Microsoft Visual Studio 2010. Построение алгоритма реализации. Класс программы, инструкция по использованию программы.

    курсовая работа [1,0 M], добавлен 26.12.2013

  • Почему C++. Возникновение и эволюция языка C++. Сравнение языков С++ и С. Эффективность и структура. Процедурное программирование. Модульное программирование. Абстракция данных. Объектно-ориентированное программирование. Улучшенный С.

    реферат [26,4 K], добавлен 03.06.2004

  • Понятие алгоритма и его характеристики как основного элемента программирования. Формы представления алгоритмов, основные алгоритмические структуры. Структурное и событийно-ориентированное программирование. Объектно-ориентированное программирование.

    реферат [86,0 K], добавлен 17.07.2008

  • Методология объектно-ориентированного программирования в Java. Понятия класса, объекта и объектной переменной. Динамическая и статическая объектные модели. Логическое структурирование приложения. Наследование в Java. Отличия интерфейсов от классов.

    курс лекций [547,2 K], добавлен 01.05.2014

  • Свойства объектно-ориентированного языка программирования. Понятия инкапсуляции и наследования. Виртуальные функции и полиморфизм. Инициализация экземпляра объекта с помощью конструктора. Динамическое создание объектов. Совместимость объектных типов.

    реферат [17,0 K], добавлен 15.04.2015

  • Изучение принципов объектно-ориентированного программирования, в котором основными концепциями являются понятия классов и объектов. Свойства этого вида программирования: инкапсуляция, полиморфизм, наследование. Описание класса. Конструкторы и деструкторы.

    презентация [74,8 K], добавлен 14.10.2013

  • Понятие объектно-ориентированного программирования, общая характеристика языков высокого уровня. Разработка программного обеспечения для реализации компьютерной игры "пинбол" с помощью императивного программирования в среде Microsoft Visual Basic.

    курсовая работа [428,9 K], добавлен 19.09.2012

  • Характеристики и свойства языков программирования. Исследование эволюции объектно-ориентированных языков программирования. Построение эволюционной карты механизмов ООП. Разработка концептуальной модели функционирования пользовательского интерфейса.

    курсовая работа [2,6 M], добавлен 17.11.2014

  • Основная цель технологии СОМ (объектная модель компонентов) - обеспечение возможности экспорта объектов. Объектно-ориентированное программирование и его место в программировании. Принципы и применение описаний информационных систем (UML и аналоги).

    курсовая работа [698,3 K], добавлен 09.12.2013

  • Определение ООП, его основные концепции. Инкапсуляция как свойство системы, позволяющее объединить данные и методы, работающие с ними в классе. Пример наследования и полиморфизма. Чисто виртуальная функция. Особенности реализации, взаимодействие объектов.

    презентация [65,2 K], добавлен 05.01.2014

  • Объектно-ориентированное программирование, операторы SQL. Создание базы данных поступабщих с помощью .NET технологии, WPF и MS SQL Server. Структура системы: хранение логинов и паролей, безопасность, системные требования. Руководство пользователя.

    курсовая работа [1,2 M], добавлен 14.12.2010

  • Особенности объектно-ориентированного проектирования. Основные понятия объектно-ориентированного подхода. Основы языка UML, варианты его использования. Диаграммы классов и взаимодействия. Разработка диаграммы прецедентов (вариантов использования).

    курсовая работа [1,1 M], добавлен 13.05.2014

  • Характеристика модульного программирования: процедуры и функции, модули и их структура, открытые массивы и строки, нетипизированные параметры. Способы передачи параметров в подпрограммы в Borland Pascal. Объектно-ориентированное программирование.

    контрольная работа [28,9 K], добавлен 28.04.2009

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

    презентация [912,2 K], добавлен 22.10.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.