Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

chast2

.pdf
Скачиваний:
9
Добавлен:
10.06.2015
Размер:
431.28 Кб
Скачать

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

VminVmax[0][0]=VminVmax[1][0]=VminVmax[2][0]=0;

VminVmax[0][1]=5;VminVmax[1][1]=10;VminVmax[2][1]=20;

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

int Zn=(FV0[2]>0)?1:-1;//мы запоминаем признак начального движения точки (1-вверх;-1-вниз) if(FV0modul<VminVmax[c][0]){FV0[0]=FV0[1]=0;FV0[2]=VminVmax[c][0]*Zn;} if(FV0modul>VminVmax[c][1]){FV0[0]=FV0[1]=0;FV0[2]=VminVmax[c][1]*Zn;}

Fg=g;

}//конец конструктора №1

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

TTochka_v_pole::TTochka_v_pole(color c,odn_mass R0,odn_mass V0,int Mp)

{// до следущего коментария все операторы идентичны соответствующим операторам конструктора №1.

...

// далее устанавливается ускорение свободного падения в зависимости от цвета точки. switch(c)

{case green:Fg=10;break; case red:Fg=5;break; case white:Fg=2;

}

}//конец конструктора №2

Далее дадим псевдокоды вспомогательного метода.

Определение вне класса вспомогательного метода выводящего в консольное окно работу полей. int TTochka_v_pole::Vivod_v_consol()

{<оператора вывода потока полей в cout> return 0;}

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

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

При сделанных выше предположения точка в отдельные интервалы временибудет совершать вертикальное равноускоренное или равнозамедленное движение.

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

Z0=FR0[2]; начальная высота точки V0=abs(FV0[2]) модуль начальной скорости точки g=Fg ускорение свободного падения Zmax=FmaxZ максимальная высота подъема точки

tmax=FT_maxZ первый момент выхода точки на максимальную высоту

tст=FT_Z0 первый момент столкновения точки с подстилающей поверхностью

Случай когда вектор начальной скарости направленвверх или равен 0.

Определяем момент выхода точки на максимальную высоту.

Этот момент можно определить по условию зануления скорости движения (точнее зануление вертикальной составляющей вектора скарости). В результате мы приходим к следующему уравнению для определения tmax:

V(t)=V0-gt=0 (2.3.1) tmax=V0/f (2.3.2)

Максимальная высота подъема точки определяетсятак: Zmax=Z0+V0tmax-g*tmax^2/2 (2.3.3)

После достижения максимальной высоты точка начнет равноускоренное движение вниз. Основываясьна формуле расчета длины пути проходимого точкой за время t при равноускоренном движении получим уравнение для определения момента достиженияподстилающей поверхности:

g*t^2/2=Zmax (2.3.4) tст=корень(2*Zmax/g)+tmax (2.3.5)

Случай когда вектор начальной скорости направленвниз.

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

Момент столкновения с подстилающей поверхностью: tст=(-V0+корень(V0^2+2Z0*g))/g (2.3.6)

Скорость столкновения с поверхностью: Vmax=V0+g*tст (2.3.7)

Время движения от поверхности до максимальной высоты:

дельта t=Vmax/g (2.3.8)

Момент первого выхода точки на максимальную высоту: tmax=tст+дельта t (2.3.9)

Максимальная высота подбема точки: Zmax=(g*дельта t^2)/2 (2.3.10)

Соответствующие коды метода будут иметь вид:

int TTochka_v_pole::Krit_point() {if(FV0[2]>=0){FT_maxZ=FV0[2]/Fg;//первый случай FmaxZ=FR0[2]+FV0[2]*FT_maxZ-Fg*FT_maxZ*FT_maxZ/2; FT_Z0=sqrt(2*FmaxZ/Fg)+FT_maxZ;} else{FT_Z0=(FV0[2]+sqrt(FV0[2]*FV0[2]+2*FR0[2]*Fg))/Fg;

double Vmax=-FV0[2]+Fg*FT_Z0; double Tmax=Vmax/Fg; FT_maxZ=FT_Z0+Tmax; FmaxZ=Fg*Tmax*Tmax/2;} return 0;}

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

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

int TTochka_v_pole::Fcounter=0;

В разраборанном классе имеется 2 явно определенных конструктора (№1 и №2) и один конструктор создаваемый автоматически (конструктор копирования).

Рассмотрим конкретные операторы в которых происходит неявное обращение к этим конструкторам.

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

TTochka_v_pole Point;// поскольку после имени объкта никакие параметры не указаны,то при создании объекта Point срабатывает конструктор умолчания (№1). Конструктор заполняет не все поля объекта. если это необходимо, то нужно вызвать основной метод Krit_point() для расчета всех характеристик точек хранящихся в соответствующих полях. вызов можно осуществить ,например, так:

i=Point.Krit_point();

другой пример:

TTochka_v_pole Point1(white);// поскольку после имени объекта указан фактический параметр того типа, который не совпадает с типом 1-го параметра конструктора №1, то в соответствии с правилами работы с перегружаемой функцией срабатывает конструктор№2 (конструктор приведения типов).

Теперь можно пояснить симантику термина "конструктор приведения (преобразования) типов": В рассматриваемом примере входом в конструктор явл данные типа color,а конструктор создает и возвращает данные классового типа, т.е. объект, т.е. возвращает значение другого типа.

Далее рассмотрим случай когда в роли конструктора приведения типов работает конструктор №1,т.е. конструктор общего вида со всеми параметрами заданными со значениями по умолчанию.

odn_mass AR01={0,0,20};// новый вариант начальных координат точки odn_mass AV01={0,0,-10};// новый вариантначального вектора скорости

TTochka_v_pole Point2(AR01,AV01);// здесь будет использоваться конструктор №1, но в качестве конструктора приведения типов

Рассмотрим случай использования указателя на объект при создании безимянного объекта с помощью операции new.

TTochka_v_pole* PtrPoint;//уазатель на объект типаTTochka_V_pole

PtrPoint=new TTochka_v_pole(red);//операция new создает безымянный объект к которому можно добраться только по адресу, при этом срабатывает конструктор №2. Адрес объекта будет передан указателю PtrPoint

Пример обращения к методу от имени безымянного объекта через его адрес

i=PtrPoint->Krit_point();//по указателю вызываем метод класса,который заполнит другие поля безымянного объекта.

____________________________________________________________________________________

47.Конструкторы копирования.Побитовое (поверхностное)копирование, опасности связанные стаким копированием.Глубокое копирование.Особенности работы сресурсоемкими объектами (имеющими динамически создаваемые поля)(из п.2.3.4.лекций выбрать часть материала, необходимую для раскрытия перечисленных вопросов).

____________________________________________________________________________________

Опредилим еще один объект Point3 при создании которого будет вызываться конструктор №2. TTochka_v_pole Point3(white);// работает конструктор №2

i=Point3.Krit_point();// заполняем другие поля Point3

Далее можно проиллюстрировать работу конструктора копирования,причем будем использовать конструктор копирования который неявно создается компелятором,а именно мы создадим Point4 который инициализируем уже созданным объектом Point3.

TTochka_v_pole Point4=Point3;//здесь неявно будемвызывать конструктор копирования, который скопирует все значения полей объекта Point3 в область памяти сохдаваемого объекта Point4.

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

-при передачи объекта в функцию по значению

-при возврате объекта из функции

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

Если у объкта есть поля являющиеся указателями или ссылками на динамически создаваемые переменные (обл памяти) то автоматически создаваемый конструктор скопирует только адрес хранящийся в поле указателя, но область на которую ссылается указатель. Он ее просто не увидит (поэтому иногда для характеристики такого копирования применяют термин "поверхностное копирования"). В резульиаие сложится ситуация когда поля указателей двух объектов будут ссылаться на одну и ту же область памяти. Может быть по существу задачи это правильно, но может оказаться что это не соответствует логике моделируемого алгоритма. Может образоваться "висячая ссылка",а именно если один из объектов уничтожит общую динамическую область, то его поле указатель получит значение 0, но при этом у поля указателя другого объекта сохранится предыдущее значение,а именно адрес области котоая уже не ппрринадлежит программе.И при прпытке обратиться к этой области возникнет ошибка и аварийное заверщение программы. Для исключения таких ситуаций прогоаммист должен сам создать конструктор копирования, который увидит также и динамическую область памяти на которую ссылается копируемый объект и следовательно он сможет ее скопироватьв свою динамическую область (в этом случае совершается "глубокое копирование").

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

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

Модифицируем класс TTochka_v_pole. -Добавим поле указатель

char* Fname1;//адрес области где будет хранится имя точки

-Имея ввиду дальнейшую иллюстрацию работы диструктора определим еще одно статическое поле. static int FLivePoint;// счетчик "живых",т.е. созданных и неуничтоженных точек.

В начале опредилим еще один конструктор приведения типов №3 (в принципе можно было просто модифицировать конструктор №3). В этом новом конструкторе будут операторы создания и инициализации динамической области для хранения имени объекта. В классе объявим прототип конструтора №3 приведения типов. Данный конструктор устроен подобно конструктору №2. Отличие: первый констркуктор предназначен для передачи в конструктор имени точки.

TTochka_v_pole(Char* name0,color c,odn_mass R0=AR0,odn_mass V0=AV0,name_mass name2=STDname,int Mp=1);

typedef char name_mass[20];// определяем новый тип name_mass STDname={'в','а','н','я'};

Дадим определение конструктору №3 вне класса.

TTochka_v_pole::TTochka_v_pole(char* name0,color c,odn_mass R0,odn_mass V0,name_mass name2,int Mp); {...

<повторяем все операторы из конструктора №2> //далее идут новые операторы FLivePoint;//счетчик живых точек

Далее формируем динамическую область памяти для хранения имени точки.

Fname1=new char[strlen(name0)+1];//формируем динамический символьный массив,а 1- это ячейка для терминального 0,т.к. нам нужна строка в стиле с.

strcpy(Fname1,name0);//копируем передавемое в конструктор строковое представление имени в созданную динамическую область.

Создадим свой конструктор копирования (№4) который будет правильно копировать данные одного объекта в новый объект создавая при этом для нового свою динамическуюпеременную. Внутри класса объявим прототип конструктора №4.

TTochka_v_pole(Const TTochka_v_pole & P);//параметром является ссылка на объект типа TTochka_v_pole

Дадим полное определение этого конструктора вне класса. Причем Fname1 полностью обрабатывается только в конструкторе №3,а именно там создается динамическая область памяти,в нее заносится конкретное имя и поле получает адрес этой области. В другом конструкторе задание имени создаваемого объекта может и непредусмптриваться. Например в конструкторе №1 можно было бы предусмотреть оператор Fname1=0, а это значит что по логике работы алгоритма будут обрабатываться безымянные точки, а значит в конструкторе надо этот факт предусмотреть. Например если этот копируемый объект моделирует безымянную точку,т.е. динамическая область для хранения имени в этом объектене создается,то и в новом объекте это делать не надо. Такая логика алгоритма поддерживается следующим конструктором копирования.

//вариант конструктора №4 (конструктор копирования) TTochka_v_pole::TTochka_v_pole(const TTochka_v_pole & P) {if (P.Fname1){// если адрес !=0 то

Fname1=new char[strlen(P.Fname1)+1]// создаем динамическую область и для нового объекта и strcpy(Fname1,P.Fname1);}// копируем туда имя нового объета

else Fname1=0;

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

Fcounter++;

Fnum=Fcounter;

FLivePoint++;

//далее буквально копируем остальные поля for(int i=0;i<3;i++){FR0[i]=P.FR0[i];FV0[i]=P.FV0[i];}

...

};// конец конструктора №4

_____________________________________________________________________________________

48.Деструкторы.

_____________________________________________________________________________________

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

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

-для локальных объектов при выходе из блока в котором он объявлен

-для глобального объекта в конце работы функции main

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

Имя деструктора начинается с ~ после которого идет имя класса без пробела.

Диструктор:

-не имеет аргументов и не возвращает никакого значения

-он не может быть определен со спецификаторамиconst и statik

-не наследуется

-он не может быть вертуально

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

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

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

-дикременировать счетчик живых объектов

-желательно отправлять в консольное окно сообщение о номере точки которая померла

Объявление в классе прототипа диструктора ~TTochka_v_pole();// (1)

Определение диструктора вне класса TTochka_v_pole::~TTochka_v_pole(){//(2) FLivePoint--;

//сообщаем на экран номер уничтожаемой точки cout<<"уничтожается точка №"<<Fnum<<endl;//(3) //сообщаем имя уничтоженой точки если оно было if (Fname1){cout<<"по имени \"";//(4)

int i=0;//(5)

while (*(Fname1+i)!='\0')//(6) cout<<*(Fname1+i++);//(7) cout<<"\""<<endl;}//(8)

//уничтожаем динамическую область если она создавалась if(Fname1){delete[]Fname1;}//(9)

};// конец диструктора

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

____________________________________________________________________________________

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

____________________________________________________________________________________

Поля данных это практически инкапсулированные вобъект ( не статические) или в класс в целом (статические поля) переменые.

Как и обычные переменные они могут относится к разным типам языка С++ (с некоторыми ограничениями). Они могут оснащаться при необходимости дополнителтными атрибутами.Поля делятся на 2 вида:

-нестатические (обычные)

-статические (объявляются со спецификатором statik)

Принципиальное различие полей этих 2х видов таково:

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

-статические поля создаются в единственном экземпляре и они находятся в общем пользовании длявсех объектов данного класса.

Необходимо четко понимать что в отличие от обычной переменной опрделение поля фактически разбивается на 2 этапа:

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

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

-для статических полей в процессе их инициализации как глобальных переменных

Напомним суть последнего процесса. В пункте 2.3.2мы приводим пример статического поля Fcounter предназначенного для подсчета количества точек.Приводился так же оператор инициализации этого поля. int TTochka_v_pole::Fcounter=0;//(1)

Укажем основные особенности этого оператора

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

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

-этот оператор должен задаваться только глобально.

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

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

-если поле объявлено со спецификатором доступа public то к нему можно обратиться по имени

Примеры

Point.FmaxZ //обращение к полю непосредственноот имени объекта (. выбор элемента по имени) PtrPoint->FmaxZ// обращение к полю по уазателю на объект с использованием операции "выбор элемента по указателю".

Константные поля.

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

const int Kol_point;//(4)

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

Например Начало внешнего определения конструктора №1 должно быть таким

TTochka_v_pole::TTochka_v_pole(odn_mass R0,odn_mass V0,int Mp,color c,double g):Kol_point(10)//(5) обращаться к таким полям можно только для чтения.

____________________________________________________________________________________

50.Методы.Основные правила работы сметодами.Константные методы.Статические методы.

____________________________________________________________________________________

Далее кратко повторим основные работы с методами в С++:

-метод - это фукция определенная внутри класса

-в определения класса метод может быть либо определен полнолстью и тогда он является встроенной функцией (inline), либо объявлен как прототип и тогда вне класса необходимо давать его полное внешнее определение.

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

Пример

Point.Krit_point();//(1) вызов метода непосредственно от имени объекта с использованием операции "."

PtrPoint->Krit_point();//(2) вызов метода по указателю на объект с использованием операции -> (выбор элемента по указателю)

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

Помимо обычных методов в классе можно определить константные и статические методы.

Константные методы.

-объявляются с ключевым словом const после списка параметров

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

-могут вызывать только константные методы

-они могут вызываться от имени любых не только константных объектов.

Статические методы.

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

Пусть в классе TTochka_v_pole дополнителтно объявлен прототип статического метода.

statik void Print_Counter2();//(3) назначение которого выводить в консольное окно значения счетчиков FCounter и FLivePoint.

Тогда полное определение этого метода вне класса должно быть таким: void TTochka_v_pole::PrintCounter()//(4)

{cout<<"поле FCounter="<<FCounter<<endl;//(5) cout<<"поле FLivePoint="<<FLivePoint<<endl;}//(6)

Обратится к этому методу можно например так:

TTochka_v_pole::PrintCounter();//(7) обращение от имени класса

Point4.PrintCounter();//(8) обращение от имени объекта

Другие особенности статических методов:

-в их теле непосредствено можно обратится только к статическим полям и методам.

-они не могут быть константными (const) или виртуальными (virtual).

___________________________________________________________________________________

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

___________________________________________________________________________________

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

Point4.Vivod_v_consol();//(1) от имени объекта Point4 обращаемся к открытому нестатическому методу Vivod_v_consol. Один из операторов внутри методатаков:

cout<<FmaxZ;//(2) здесь к полю FmaxZ обращаемся не указывая имени объекта.

Вопрос: как компелятор догадывется , что в операторе 2 имеется ввиду,чтополе FmaxZ и именно объекта

Point4?

Причина в том, что согласно правилам языка С++ в каждой нестатический метод передается скрытый параметр this. Синтаксически это служебное слово. В нем хранится константный указатель именно на тот объект,от которого былвызван нестатический метод ( у нас это Point4). ИМенно этот указатель неявно используется внутри метода для ссылок на элементы объекта. Благодаря этому при компеляции программы оператор из строки 2 превращается в

cout<<this->FmaxZ;//(3) т.е. обращение к полю FmaxZ будет от объекта Point4.

Оператор в форме 3 можно описать явно вместо 2, но в этом нет необходимости.

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

Например Когда мы хотим сформировать односвязный список элементами которого являются объекты.

Указатель здесь не передается и это понятно поскольку к такому методу можно обратится не только от имени объекта, но и от имени класса.

Общее замечание:

Помимо рассмотренных выше конструкций С++ допускает использовать указатели на поля данных и на методы класса с помощью операций "." и ->.

___________________________________________________________________________________

52.Дружественные функции и классы.

____________________________________________________________________________________

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

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

Правило работы с дружественными функциями.

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

2.Дружественная фукция имеет доступ ко всем эл класса.

3.Одним из параметров фукции обязательно должен быть

или указатель на объект с поля которого фукция должна работать или ссылка на этот объект.

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

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

5.Одна и таже фукция может бытьдружественной нескольким классам.

Для примера объявим в классе TTochka_v_pole дружественную функцию Zamena_g которая будет предназначена для замены значения ускорения свободного падения.

friend void Zamena_g(TTochka_v_pole*,double)// в пртотипе имена параметров можно не указывать

Определение вне класса дружественной функции например таково void Zamena_g(TTochka_v_pole* P,double gnew)

{P->Fg=gnew;}

ПРимер вызова дружественной функции

Zamena_g(&Point4,20);

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

Пусть мы хотим сделать все методы класса А дружественными другому классу В. Тогда весь класс А надо объявит как дружественный классу В.

Пример

Class B{

...

friend class A;

}

class A{

...

void f1(); void f2();

}

При таких объявлениях методы f1 f2 будут дружественными классу В, хотя они объявлены без спецификатора friend.

Общие замечания

1. Спецификатор friend не является спецификатором доступа и не наследуется.

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

___________________________________________________________________________________

53.перегрузка операций - общие положения.

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