Краткий обзор основных парадигм программирования 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Краткий обзор основных парадигм программирования



Основные принципы ООП

 

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

 

При создании программного комплекса необходимо разработать опреде-ленные абстракции.

 

Пример: Задача составления расписания занятий.

 

Необходимые абстракции: студент, курс лекций, преподаватель, аудитория.

 

Операции:

 

− Определить студента в группу

 

− Назначить аудиторию для группы

 

−..........

 

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

 

Практически все сложные системы иерархичны, и уровни их иерархии от-ражают различные уровни абстракции. Для каждой конкретной задачи рассмат-

 

 

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

 

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

 

Во всех объектно -ориентированных языках программирования реализованы следующие основные механизмы (постулаты) ООП:

 

Инкапсуляция

 

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

 

Полиморфизм

 

Все эти механизмы важны для разработки и использования абстракций.

 

1) Инкапсуляция –механизм,связывающий вместе код и данные,кото-рыми он манипулирует, и одновременно защищающий их от произвольного доступа со стороны другого кода, внешнего по отношению к рассматриваемому. Доступ к коду и данным жестко контролируется интерфейсом.

Основой инкапсуляции при ООП является класс.

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

2) Наследование –механизм,с помощью которого один объект(произ-водного класса) приобретает свойства другого объекта (родительского, базового класса). При использовании наследования новый объект не обязательно описы-вать, начиная с нуля, что существенно упрощает работу программиста. Наследо-вание позволяет какому-либо объекту наследовать от своего родителя общие ат-рибуты, а для себя определять только те характеристики, которые делают его уникальным внутри класса.

Наследование есть очень важное понятие, поддерживающее концепцию иерархической классификации.

3) Полиморфизм –механизм,позволяющий использовать один и тот жеинтерфейс для общего класса действий.

 

Пример: Имеются3типа стека для хранения:

 

o целых чисел

 

o чисел с плавающей точкой o символов

 

Вместо трех подпрограмм управления в объектно-ориентированной про-грамме требуется всего одна подпрограмма (один интерфейс)

 

Общая концепция полиморфизма: один интерфейс – много методов. Выбор конкретного действия (метода) применительно к конкретной ситуа-

 

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

 

 

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

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

Абстрактные типы данных

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

Рактным типом данных (АТД).

В С++ АТД реализуется с помощью классов, в которых нет открытых чле-нов-данных, то есть вся структура этих классов скрыта от внешнего пользователя.

 

3. Классы и объекты С++

 

Центральным понятием ООП является класс. Класс используется для опи-сания типа, на основе которого создаются объекты (переменные типа класс).

 

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

 

 

Синтаксис описания класса

 

class Имя_класса { определение_членов_класса };

 

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

 

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

 

Класс как область видимости

 

Класс является областью видимости описанных в нем членов класса. Иден-тификатор члена класса локален по отношению к данному классу. Классы могут быть вложенными. Одноименные идентификаторы членов класса закрывают видимость соответствующих внешних идентификаторов.

 

Операция '::' позволяет получить доступ к одноименным объектам, внешним по отношению к текущей области видимости, в частности, к глобальным функциям и переменным, следующим образом:

 

имя_класса:: имя_члена_класса или

 

:: имя - для имен глобальных функций и переменных.

 

Пример:

 

int ia1;

 

void f1(int b1) {ia1 = ia1 + b1;

 

}

 

class x {

 

int ia1; public:

 

x(){ia1 = 0;} void f1(int b1){

 

::f1(b1); // вызов глобальной функции

 

}

 

};

 

int main(){x a2; a2.f1(2); return 0;

 

}

 

3.6. Объявление и определение методов класса. Спецификатор inline

 

Каждый метод класса, должен быть определен в программе. Определить метод класса можно либо непосредственно в классе (если тело метода не слишком сложно и громоздко), либо вынести определение вне класса, а в классе только объявить соответствующий метод,указав его прототип.

 

При определении метода класса вне класса для указания области видимости соответствующего имени метода используется операции ‘::’:

 

Пример:

 

class x {

 

int ia1; public:

 

x(){ia1 = 0;} int func1();

};

 

int x::func1(){ … return ia1; }

 

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

 

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

 

inline int func1();

 

Такие функции называются встроенными.

 

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

 

По определению методы класса, определенные непосредственно в классе, являются inline -функциям

 

3.7. Указатель this

 

В классах С++ неявно введен специальный указатель this – указатель на текущий объект. Каждый метод класса при обращении к нему получает данный указатель в качестве неявного параметра. Через него методы класса могут по-лучить доступ к другим членам класса.

 

Указатель this можно рассматривать как локальную константу, имеющую тип X*, если X – имя описываемого класса. Нет необходимости использовать его явно. Он используется явно, например, в том случае, когда выходным значением для метода является текущий объект.

Данный указатель, как и другие указатели, может быть разыменован.

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

 

Пример:

 

class x {

 

...

 

public:

 

x& f(...){

 

...

 

return * this;

 

}

 

};

 

Указатель на член класса

 

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

 

class X {

 

 

int i; public:

Х(){i = 1;} int f1(int j){

 

cout << "print i" << i << "\n"; return j;

}

 

int f2(int j){

 

cout << "reset i \n"; i = 1; return j;

}

 

int f3(int j){

 

cout << "set i \n"; i = j; return j;

}

 

};

 

typedef int (Х::* pf)(int); // см. комментарий 1)

 

intmain(){    
intk, sw, par;    
x b; // см. комментарий 2)  
pf ff;  
...    
switch(sw){ // см. комментарий 3)  
case1: ff=&x::f1;  
break;    
case2: ff=&x::f2;    
break;    
case3: ff=&x::f3;    
}; // см. комментарий 4)  
k = (b.*ff)(par);  
...    
return0;    
}    
Комментарии:    

 

1) ключевое слово typedef вводит новое имя для типа:

 

typedef int (Х::* pf)(int);-pf–тип указателя на методкласса X с одним входным параметром типа int и типом возвращаемого значения – int.

 

2) pf ff; – создание объекта ff, имеющего введенный тип p f.

 

3) ff = &Х::f1; – указателю ff присваивается адрес одного из методов класса. Доступ к этому методу по данному указателю через какой-либо объект невозможен (оператор ff = &b.f1; – неверен). Дело в том, что -указатель на член класса представляется для нестатических членов не

 

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

 

4) k =(b.* ff)(par); – разыменование указателя на нестатический метод класса дает доступ к коду по относительному адресу, который применяется к базовому адресу конкретного объекта (в данном случае – объекта b).

 

Примечание. В случае объявления методов статическими членами(см.раздел«Статические члены класса») идентификатор pf необходимо объявить обычным указа-телем на функцию:

 

typedef int (* pf)(int);

 

Разыменование объекта такого типа представляется обычным разыменованием указа-теля на функцию:

 

k = (*ff)(par);

 

Применение техники разыменования указателя на метод класса является проявлением динамического полиморфизма, когда исполняемый код для одного и того же оператора (k = (b.*ff)(par)) определяется на этапе исполнения, а не компиляции. В большей мере динамический полиморфизм реализуется вир-туальными функциями,описываемыми в следующих разделах.

 

Конструкторы и деструкторы

 

Конструкторы и деструкторы являются специальными методами класса Конструкторы вызываются при создании объектов класса и отведении па-

 

мяти под них.

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

 

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

 

Так как конструкторы и деструкторы неявно входят в интерфейс объекта, их следует располагать в открытой области класса.

 

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

 

Отличия и особенности описания конструктора от обычной функции:

 

1) Имя конструктора совпадает с именем класса

 

2) При описании конструктора не указывается тип возвращаемого значения

 

 

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

 

В описании конструктора тип возвращаемого значения не указывается не потому, что возвращаемого значения нет. Оно как раз есть. Ведь результатом работы конструктора в соответствии с его названием является созданный объект того типа, который описывается данным классом. Страуструп отмечал, что кон-структор – это то, что область памяти превращает в объект.

 

Конструкторы можно классифицировать разными способами:

 

1) по наличию параметров:

 

− без параметров,

 

− с параметрами;

 

2) по количеству и типу параметров:

 

− конструктор умолчания,

 

− конструктор преобразования,

 

− конструктор копирования,

 

− конструктор с двумя и более параметрами.

 

Набор и типы параметров зависят от того, на основе каких данных создается объект.

 

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

 

Деструкторы применяются для корректного уничтожения объектов.Частопроцесс уничтожения объектов включает в себя действия по освобождению вы-деленной для них по операциям new памяти.

 

Имя деструктора: ~ имя_класса У деструкторов нет параметров и возвращаемого значения.

 

В отличие от конструкторов деструктор в классе может быть только один.

 

Пример: Описание класса.

 

class box{

 

int len, wid, hei; public:

box(int l, int w, int h){

 

len = l; wid = w; hei = h;

 

}

 

box(int s){

 

len = wid = hei = s;

}

 

box(){

len = 2; wid = hei = 1;

 

}

int volume(){

 

return len * wid * hei;

}

 

};

 

Конструктор умолчания

 

Конструктор без параметров называется конструктором умолчания.

 

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

 

class Х{ };

 

Х x1;

 

Замечание:роль конструктора умолчания может играть конструктор,у ко-торого все параметры имеют априорные значения, например:

 

box (int l = 24, int w = 12, int h = 6);

 

4.2. Конструктор преобразования и конструкторы с двумя и более параметрами

 

Если для создания объекта необходимы параметры, то они указываются в круглых скобках после идентификатора переменной:

 

box b2(1,2,3); box b3(5);

 

Указываемые параметры являются параметрами конструктора класса. Если у конструктора имеется ровно один входной параметр, который не представляет собой ссылку на свой собственный класс, то соответствующий конструктор на-зывается конструктором преобразования. Этот конструктор называется так в связи с тем, что в результате его работы на основе объекта одного типа создается объект другого типа (типа описываемого класса).

 

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

 

X(T);

 

X(T&);

 

X(const T&);

 

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

 

 

Примечание. Выделение в отдельную группу конструкторов с двумя и более па-раметрами, независимо от их типа, является в некотором смысле, условным. Так, на-пример, если есть два класса: Vector и Matrix, то для создания соответствующих объектов:

 

Vector v1(10);

 

Matrix m1(10,15);

 

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

 

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

 

Пример:

 

class X { int x1;

 

public:

 

X(int px1 = 0}

 

};

 

Для такого класса будут верны следующие объявления объектов:

 

int main(){

 

… Х x1, x2(1); …

 

}

Конструктор копирования

 

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

 

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

 

менных встроенных типов с использованием операции присваивания совместно с объявлением объекта:

 

box b5(2,4,6); // создание объекта типа box с // использованием числовых данных

box b6 = b5; // создание объекта b6 – копии объекта b5

 

Если инициализация производится объектом такого же типа, то объ-ект-инициализатор также может быть указан в круглых скобках после иденти-фикатора создаваемого объекта:

 

box b7(b5);

 

Свод ситуаций, в которых используется конструктор копирования, описаны ниже.

 

Если класс не предусматривает создания внутренних динамических струк-тур, например, массивов, создаваемых с использованием операции new, то в конструкторе копирования достаточно предусмотреть поверхностное копиро-вание,то есть почленное копирование информационных членов класса.

 

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

 

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

 

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

 

Пример: Для класса stack конструктор копирования может быть опреде-лен следующим образом:

 

class stack { char * c1;

int top, size; public:

stack(int n = 10){ size = n;

top = 0;

c1 = new char [size];

 

}

 

stack(stack & s1);

...

};

 

stack::stack(stack & s1){ size = s1.size;

 

top = s1.top;

 

c1 = new char [size];

 

for (int i = 0; i < size; i++)c1[i] = s1.c1[i];

 

}

 

Замечания по работе конструктора копирования:

 

1) Входной параметр является внешним объектом по отношению к созда-

 

ваемому объекту. Тем не менее, имеется возможность прямого обраще-ния к закрытым членам этого внешнего объекта. Это возможно только потому, что входной параметр имеет тип, совпадающий с типом созда-ваемого в результате работы конструктора копирования объекта. Если бы на вход конструктора поступал бы объект другого типа (например, в конструкторе преобразования класса vector входным параметром был бы объект, созданный на основе класса matrix), то для доступа к за-крытым членам объекта-параметра необходимо было бы применять специальные средства. Это связано с тем, что единицей защиты явля-ется не объект, а тип, то есть методы объекта могут обращаться к за-крытым членам не только данного объекта, но и к закрытым членам любого объекта данного типа.

 

2) В момент описания конструктора копирования класс, как тип данных, еще не описан до конца. Тем не менее, идентификатор класса уже ис-пользуется в качестве полноценного типа данных при описании входного параметра конструктора копирования. Такая технология схожа с опи-санием рекурсивной функции, когда тело описываемой функции со-держит вызов этой же функции.

 

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

 

Х(Х&);

 

Х(const Х&);

 

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

 

Пример:

 

box* b4 = new box(2,3,5); // Явный запуск конструктора

 

  // с тремя параметрами. Адрес  
  // динамически созданного  
  // объекта типа box  
  // присваивается переменной  
box b5 = * b4; // b4.  
// Разыменование указателя на объект,  
  // т.е. получение доступа к  
  // информации, хранящейся в нем, и  
  // использование ее для инициализации  
  // создаваемого объекта.  

box b6 = box(4,7,1); // Создание временного объекта и

 

// инициализация именованного

 

// объекта.

 

Статические члены класса

 

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

 

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

 

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

 

имя_класса:: имя_функции (фактические_параметры);

 

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

 

Примечание 1. Статические методы класса не могут вызывать нестатические,таккак последние имеют доступ к данным конкретных объектов. Обратное допустимо: не-статические методы могут вызывать статические методы.

 

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

 

Примечание 3. Статические методы класса не могут быть виртуальными и кон-стантными (inline–функциями быть могут).

 

Пример:

 

#include <iostream> using namespace std;

 

class X{X(){} ~X(){}

 

public:

 

static X& createX(){

 

X* x1 = new X;

 

cout << "X created" << endl; return *x1;

}

 

static void destroyX(X& x1){ delete &x1;

 

cout << "X destroyed" << endl;

 

}

 

};

 

int main(){

 

X& xx1 = X::createX();

 

...

 

X::destroyX(xx1); return 0;

}

 

Статические информационные члены класса, даже находящиеся в закрытой области (а это характерно для информационных членов класса в соответствии с принципом инкапсуляции), необходимо объявить дополнительно вне класса (с возможной инициализацией):

 

тип_переменной имя_класса:: идентификатор = инициализатор;

 

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

 

Пример:

 

class B {

 

static int i; // статический информационный член

// класса

 

public:

 

static void f(int j){ //статический методi = j;

 

}

 

};

 

int B::I = 10; // дополнительное внешнее определение

 

// статической переменной с

// инициализацией статического

// информационного члена класса b.

 

int main(){B a;

...

 

B::f(1); // вызов статической функции-члена класса.

 

...

 

return 0;

 

}

 

Друзья классов

 

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

 

Друг класса – это функция, не являющаяся членом класса, но имеющая доступ к его закрытым и защищенным членам.

 

Друзья класса объявляются в самом классе с помощью служебного слова friend. в любой области доступа.

 

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

 

Пример:

 

class B; //предварительное объявление идентификатора// b как идентификатора типа данных

 

class X { int ia1;

 

public:

 

X(){

 

ia1 = 0;

}

int func1(b& bb);

 

};

 

class B { int b1;

 

public:

 

friend int X::func1(B & bb);B(){

 

b1 = 1;

 

}

 

};

 

int X::func1(B & bb){ia1 = ia1 + bb.b1; return ia1;

 

}

 

int main(){ int i1;B b2;

 

X a2;

 

i1 = a2.func1(b2); return 0;

 

}

 

Примечание. Несмотря на предварительное объявление идентификатора B, егоможно использовать в описании класса X, находящемся перед описанием класса B,

 


только в описании формального параметра в прототипе функции (func1). Саму функ-цию func1 необходимо описывать вне класса X после описания классов B и X, ис-пользуя операцию разрешения области видимости ‘::’ с квалификатором X. Непра-вильным будет следующее описание функции func1:

 

class B;

 

class X {

 

int ia1; public:

 

X(){

 

ia1 = 0;

 

}

 

int func1(B & bb){

 

ia1 = ia1 + bb.b1; // ОШИБКА! return ia1;

 

}

 

};

 

class B {

 

int b1; public:

 

friend int X::func1(B & bb);B(){

 

b1 = 1;

 

}

 

};

 

int main(){ int i1;B b2;

 

X a2;

i1 = a2.func1(b2); return 0;

 

}

 

Другом можно объявить и весь класс: friend classХ;

 

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

 

friend имя_функции (список_формальных_параметров);

 

Пример:

 

class B;

 

class D { int x;

...

friend void func(B &, D &); //функция дружественнаклассу D

 

...

 

};

 

class B { int y;

...

 

friend void func(B &, D &); //функция дружественна// классу B

 

...

 

};

 

void func (B & b1, D & d1) {

 

cout << d1.x + b1.y; // дружественная функция имеет // доступ к закрытым // компонентам обоих классов

 

}

 

Статический полиморфизм

 

Статический полиморфизм реализуется с помощью перегрузки функций и операций. Под перегрузкой функций в С++ понимается описание в одной об-ласти видимости нескольких функций с одним и тем же именем.О перегрузкеопераций в С++ говорят в том случае, если в некоторой области видимости по-является описание функции с именем operator <обозначение_операции_С++>, задающее еще одну интерпретацию заданной операции.

 

Перегрузка унарных операций

 

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

 

Перегрузка функций

 

Имеется возможность описывать р



Поделиться:


Последнее изменение этой страницы: 2017-02-05; просмотров: 277; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.21.76.0 (0.421 с.)