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



страница3/15
Дата17.04.2013
Размер1.64 Mb.
ТипУчебное пособие
1   2   3   4   5   6   7   8   9   ...   15

2. КЛАССЫ И ИХ СТРУКТУРА
Класс является основным элементом языка СИ, обеспечивающим ООП. Он представляет собой расширение структур языка СИ. В классах помимо определение данных допускаются определения выполняемых над ними функций. Кроме того, в них имеются средства управления доступа к данным, позволяющие организовать взаимодействие различных классов друг с другом и классов с обычными функциями. Функции, входящие в класс, часто называются методами.

Определение классов иллюстрирует следующий пример:

// iarray.h

class iarray

{ int maxitems // максимальное число элементов

int citems // число элементов в массиве

int *items // указатель на массив

public:

// конструктор

array(int nitems);

// деструктор

_array();

// занесение элементов в массив

int putitem(int item);

// получение элемента из массива

int getitem(int ind; int &item);

//получение фактического числа элементов в массиве

int count({return citems;});

};

В определении даны объявления внутренних переменных класса (переменные состояния), а также прототипы методов, обеспечивающих работу с данными.

Приведенный класс предназначен для создания целых массивов заданной длины и для размещения в них целых значений. Назначение переменных пояснено соответствующими комментариями.

Класс iarray содержит в себе пять методов. Прототипы четырех из них даны в файле iarray.h, а для пятого метода дана полная реализация.
Сами исходные тексты методов класса iarray приведены ниже:
// iarray.cop

# include “iarray.h”

//конструктор

iarray::iarray(int nitems)

{ items=new int[nitems];

maxitems=nitems;

citems=0;

}
//деструктор

iarray::_iarray()

{delete items;

}
//занесение элемента в массив

int iarray::putitem(int item)

{ if (citems
items[citems]=item;

citems++;

return 0;

}

else return –1;

}
//получение элемента из массива

int iarray::getitem(int ind, int &item)

{ if (ind>=0 && ind
item-items[ind];

return 0;

}

else return –1

}
Среди методов особое место занимают такие два метода, как конструктор и деструктор. С помощью конструктора, в данном случае, создается массив целых значений заданной длины. В нем фиксируется длина массива и устанавливается счетчик занятых элементов, а также производится распределение памяти под массив. Последняя операция выполняется введенным в С++ оператором new. Он проще, чем функция malloc, так как при ее применении не требуется задавать размер выполняемой памяти в байтах и преобразовывать полученный указатель к конкретному типу.


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

Методы putitem и getitem обеспечивают контролируемое обращение к элементам массива. В первом методе отслеживается возможность размещения нового элемента в массиве. Во втором - правильность задания индекса получаемого из массива элемента.

Метод count позволяет получить число включений в массив элементов. Он реализован прямо в исходном тексте заголовочного файла iarray.h.

Отметим, что при определении методов за пределами текста класса используется операция” ::”, например: int iarray::putitem()

Эта операция говорит о том, что областью действия метода putitem является класс irarray.

Коснемся теперь использования определенного нами класса. Можно привести следующий пример:

#include “iarray.h”

#include

#include

#include

int main()

{

iarray m(10);

int i,j,k;

int n;

randomize()

for (i=1;i<=s;i++)

{

m.putitem(rand());

}

n=m.count()

for(i=0;i<=n;i++){

m.getitem(i,j);

count<
}

}
В этом примере создается объект m, принадлежащий классу iarray. Далее в массив m вводятся пять целых чисел, полученных путем обращения к датчику случайных чисел. Эти числа вводятся в выходной поток count, которому соответствует дисплей.

В данном примере мы сталкиваемся с понятием объект. Объектом является переменная m, объявленная как принадлежащая классу iarray. Объект- это конкретный экземпляр массива целых чисел.

Действия с объектами осуществляются с помощью методов, обращение к которым задается составными именами, например : m.putitem() или m.getitem();

Отметим, что в объявлении iarray m(10); также производит вызов конструктора, в котором собственно и выполняются действия по созданию массива.

Есть другая возможность создания объекта с помощью оператора new. Например, в следующем фрагменте программы:

iarray *a;

iarray *b;

int n1=10

int n2=20;

a=new iarray(n1);

b=new iarray(n2);

…………

delete a;

delete b;

, где динамически создаются два массива a и b, размерностью 10 и 20 соответсвенно.
2.1. Связь класса с внешней средой
В ООП широко используются абстрактные типы данных и скрытие информации. Следовательно, проблема взаимодействия классов со средой, в которой они используются, приобретает первостепенное значение.

Решается эта проблема путем управления доступом к элементам классов с помощью использования в определениях классов ключевых слов private, public и protected.

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

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

Отметим, что элементы класса не могут иметь описателей типа памяти automatic, extern. Они могут иметь дополнительно только описание static. Элемент класса с описателем static будет общим для всех объектов данного класса.

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

class type{

private:

int prm;

public:

friend void ftype(type x,int y);

void ftype(type x,int y);

{ x.prm=y;}
В данном примере в “дружественной “ классу функции ftype осуществляется доступ к внутренней переменной prm объекта x, принадлежащего к классу type.
2.2. Отношения между классами
Одной из важнейших черт ОПП является наличие механизма наследования свойств одного класса другими классами. Он позволяет строить новые классы на базе ранее созданных и этим самым способствует повторной используемости результатов процесса программирования.

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

Рассмотрим пример, иллюстрирующий механизм взаимодействия между базовым и производными классами:

//bassear.h

class basearray

{protected:

int maxitems: //максимальное число элементов

int citems; //число размещенных элементов

public: //конструктор

basearray(int nitems){maxxitems=nitems; citems=0;};

};
//irray.h

class iarray : public basearray

{private:

int *items;

public:

iarray(int nitems); //конструктор

_iarrray(); //деструктор

int putitem(int item) //занесение элемента в массив

int getitem(int ind;int &item); // получение элемента из массива

int count({return citems;}); //получение числа элементов

};

Исходный текст методов класса iarray приведен ниже:

//iarray.cpp

#include “basearray.h”

#include “iarray.h”

iarray:iarray(int nitems):basearray(nitems) //конструктор

{items=new int[nitems];}

iarray::_iarray() //деструктор

{delete items;}

int iarray::putitem(int item) //занесение элемента в массив

{ if (citems
items[citems]=item;

citems++;

return 0;

}

else return –1;

}

int iarray:getitem(int ind,int &item) //получение элемента из массива

{ if(ind>=0 && ind
item=items[ind];

return 0;

}

else return –1;

}

int iarray::count(){return citems;}; //получение числа элементов
В новой версии реализации массива выделен базовый класс basearray, в котором определены общие для массивов составляющие, независимо от типов элементов. В производном классе определен конкретный тип массива. В нашем случае тип массива int, хотя можно определить тип массива как float, как struct и т.п.

Класс iarray наследует от класса basearray конструктор. При создании объекта типа iarray в конструкторе iarray вызывается конструктор basearray. С помощью механизма наследования осуществляется скрытие информации. Появившийся описатель protected говорит о том, что следующие за ним переменные будут доступны в производном и доступны в классах и функциях, не принадлежащим к этим классам.
2.3. Расширения языка С++
ФУНКЦИЯ inline

В функции #define проявляется много необычных эффектов связанных с многократным использованием аргументов. Все проблемы разрешила функция С++ inline, взятая из языка ADA. При обращение к функции с описателем inline не происходит реального вызова, а исполняется код функции, который транслятор вставляет непосредственно в место обращения.

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

Inline double sqr(double x){return x*x;}

Обычно функция помещается в header-файл- файл с расширением *.h, чтобы функция всегда была “под рукой” у транслятора. Другое ограничение, inline-функции не должны совершать циклы или ассемблерные вставки.
ФУНКЦИЯ OVERLOAD(ПЕРЕЗАГРУЖАЕМЫЕ)

Следующей функцией пришедшей из ADA является функция overload, позволяющая различить функции не только по имени, но и по типу аргумента, например:

double sqr(double x){return x*x;}

Обе спокойно уживаются в одной программе. При вызове будет использована одна из функций, какая решает тип аргумента.
ПАРАМЕТРЫ ФУНКЦИИ ПО УМОЛЧАНИЮ

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

print(matrix a,char *format=”%9.4”,char *title=null);

Задавать значение параметров лучше только один раз в разделе описаний.

Сделав это, обращение к функции может выглядеть так:
matrix c;

....

print(c);

или

print(c,”%12.7”);
ССЫЛКИ

Ссылка- это переменная, задаваемая указателем. Чтобы сделать переменную ссылкой, необходимо после описателя типа поставить оператор “&”. Ссылка во всем себя ведет так же, как и переменная того же типа, но при этом надо помнить, что на самом деле она совпадает с другой переменной, адрес которой указывается при объявлении ссылки, например:

int a;

int &b=&a;// переменная b совпадает с а.

Возникают ситуации, когда в функцию необходимо передавать не значения переменной, а ее адрес. Явная работа с адресами вызывает много неудобств при разработке функции и ее использовании. Теперь, при описании функции достаточно указать, что параметр передает по ссылке, и работать с ним не как с адресом, а как с переменной. Например, приведем функцию пересчета декартовых координат в полярные:

void polkar(double &x,double &y,double &FI,double &R){

R=sqrt(x*x*+y*y);

FI=atang(y,x);

}

А вот выглядит обращение к данной функции:

double X,Y,FI,R;

……..

poral(x,y,FI,R);

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

Таким образом, можно задать и тип возвращаемого значения, например:

Double &fuuc(int i);
ФУНКЦИИ- ЧЛЕНЫ СТРУКТУРЫ

Как правило, описав новую структуру, вы тут же создаете набор функций, работающих с этой структурой. Например, для структуры _3d, описывающей трехмерный вектор, можно записать функцию:

double mod(_3d &x);

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

_3d R;

double a;

…..

a=mod(R); //традиционный подход СИ

a=R.mod(); //это новый подход С++

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

Struct _3d{

double x,y,z;

double mod():

};

При описании реализации функции надо после типа возвращаемого значения указать имя структуры, членом которой является данная функция, отделив от него имя функции двойным двоеточием, например: double _3d::mod(){return sqrt(x*x+y*y+z*z);}

Покончив с формой, перейдем к содержанию. Наивно было бы думать, что создается новая копия функции для каждой новой переменной данного типа. Каждая функция представлена в единственном экземпляре и получает один срытый параметр- указатель на ту переменную, для которой она вызвана( называется рабочей переменной). К этому указателю можно обратиться по имени this. Если есть оператор а=R.mod(); то this при этом вызове соответствует адресу R, а функция mod() может быть реализована так:

double _3d::mod(){

return sqrt(this-.x*this-.x+

this-.y*this-.y+

this-.z*this-.z);}

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

Функция double _3d::proection(_3d r);

которая вычисляет длину проекции вектора R на рабочий вектор.
double _3d::proection(_3d r){

return(x*r.x+y*r.y+z*r.z)/sqrt(x*x+y*y+z*z);};
ПРИМЕР 2

Структура polar, определяет вектор в полярных координатах r,fi,l.

Для нее необходимо написать функцию _3dpoar::vect();
struct polar{

double if=cos(fi);

sf=sin(fi);

cl=cos(l),sl=sin(l);

_3d r;

r.x=r*sf*cl;

r.y=r*sf*sl;

r.z=r*if;

return r;

};


ПРИМЕР 3

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

Для нее надо описать функции:

void init(); //инициализация

void add(); //добавить элемент

double get(); //взять элемент

int free(); //величина свободного пространства

int used(); //величина занятого пространства
Буферизация, или организация очереди, - широко распространенное техническое решение. Один из способов реализации буфера - кольцевой буфер на одномерном ограниченном массиве. Идея такова. Имеется одномерный массив и две индексные переменные. Одна- индекс приемника <- указывает на элемент массива, куда записывается вновь поступающие значения. При записи индекс массива увеличивается на единицу. Вторая- индекс источника <- указывает га элемент массива из которого извлекается значение. При извлечении индекс источника тоже увеличивается на единицу. Если один из индексов выходит за границы, то он устанавливается на ее начало. В такой очереди могут стоять не только числа, но и объекты с более сложной структурой.
В соответствии с этим программа будет выглядеть так:

Struct C_Buffer{

double ptr[1024]; //массив буфера

int dest,scr; //DESTination- приемник,SouRCe- источник

void init(){src=dest==0;};

void add(double a);

double get();

int used();

int free();

};

void C_Buffer::add(double &a){

ptr[dest++]=a;

if)dest==1024)

dest=0;

};

int C_Buffer::used(){

int=dest-src;

if(n>=0)return n;

else return n+1024;

};

double C_Buffer::get(){

if(++src!=1024) return ptr[src-1];

src=0;

return ptr[1023];

};

int C_Buffer::free(){

int n=src-dest;

if(n>0) return n;

else return n+1024;

};

Функция int() нужна для инициализации указателей. Обращение к ней обязательно пред использованием буфера.
Ближайшим родственником класса является структура. Если структуру поделить механизмом наследования, то она станет классом. Механизм наследования позволяет вновь создаваемым классами данных наследовать свойства уже существующих классов. Именно способность передавать и получать свои свойства по наследству отличает класс от структуры. Синтаксически класс описывается также, как и структура: сначала идет ключевое слово class, затем имя класса, затем, в фигурных скобках, члены класса- данные или функции. Все, что сказано о структурах, справедливо и для классов. Прежде чем пользоваться механизмом наследования, преобразуем уже имеющуюся у нас структуру _3d в класс:
class _3d{

public:

double x,y,z;

double mod();

};

double _3d::mod(){return(sqrt(x*x+y*y+z*z));};

Здесь описан класс с именем 3_d. Ключевое слово public означает, что нижеследующие члены класса общедоступны. Далее описаны три действительных числа, задающих координаты вектора. Обращение к членам класса осуществляется так же, как и к членам структуры, через точку.

Для классов применяется несколько другая терминология. Если раньше (в СИ) говорили о переменной данного типа, то теперь мы будем говорить об объекте данного класса, а функции- члены класса- будем называть методами данного класса.
1   2   3   4   5   6   7   8   9   ...   15

Похожие:

Объектно-ориентированное программирование учебное пособие icon13. Основные принципы Объектно-Ориентированного Программирования (ооп) Объектно-Ориентированное Программирование
Объектно-Ориентированное Программирование это методология программирования, которая основана на представлении программы в виде совокупности...
Объектно-ориентированное программирование учебное пособие iconОбъектно-ориентированное программирование на языке Delphi
Методическое пособие предназначено для изучения основ объектно-ориентированного языка программирования Delphi (ооп) без ориентации...
Объектно-ориентированное программирование учебное пособие iconОбъектно-ориентированное программирование

Объектно-ориентированное программирование учебное пособие iconВизуальное объектно-ориентированное программирование. Графический интерфейс: форма и управляющие элементы

Объектно-ориентированное программирование учебное пособие iconСоздание web-сайтов, разработка программного обеспечения, объектно-ориентированное программирование, проектирование баз данных

Объектно-ориентированное программирование учебное пособие iconИнтегрированная среда разработки языка Visual Basic
...
Объектно-ориентированное программирование учебное пособие iconКурс: Объектно-ориентированное программирование
Напишите программу для общения через Internet. Программа должна состоять из двух частей: сервер и клиент. Сервер стартует в качестве...
Объектно-ориентированное программирование учебное пособие iconПрограммирование простых типов данных
Учебное пособие предназначено для студентов физического факультета, изучающих курс "Программирование и вычислительная физика"
Объектно-ориентированное программирование учебное пособие iconЗадание к лабораторным работам по курсу “Объектно-ориентированное программирование”
Разработать структуру элементов данных класса в виде динамической структуры данных (динамический массив, список, массив указателей)....
Объектно-ориентированное программирование учебное пособие iconУчебное пособие Уфа 2006 удк 519. 8 Б 19 ббк 22. 1: 22. 18 (Я7)
Бакусова С. М. Математика. Часть Математическое программирование / Учебное пособие. Уфа: ООО полиграфстудия «Оптима», 2006. – 71...
Разместите кнопку на своём сайте:
ru.convdocs.org


База данных защищена авторским правом ©ru.convdocs.org 2016
обратиться к администрации
ru.convdocs.org