- •1 Перегрузка функций
- •Шаблоны функций
- •Void main()
- •3 Класс — как расширенное понятие структуры
- •4 Конструкторы, деструкторы и доступность компонентов класса
- •Void main ( )
- •5 Компонентные данные
- •8 Друзья классов
- •7 Указатель this
- •Void main()
- •9 Перегрузка стандартных операций
- •Void main ()
- •10 Простое наследование
- •11 Виртуальные функции и абстрактные классы
- •12 Абстрактные классы
- •13 Множественное наследование
- •Void main()
7 Указатель this
При вызове функции, принадлежащей классу, для обработки данных конкретного объекта, этой функции автоматически передается указатель на тот объект, для которого функция вызвана. Этот указатель имеет фиксированное имя this и (“тайно”) определен в каждой функции класса следующим образом:
имя_класса *const this = адрес_объекта;
Изменить указатель this нельзя, так как это константный указатель. Он указывает именно на тот объект, для которого функция вызывается. This —является дополнительным (скрытым) параметром каждой нестатической компонентной функции. Объект, который адресуется указателем this, становится доступным внутри принадлежащей классу функции именно с помощью указателя this.
При совпадении имени компонента класса с именем формального параметра принадлежащей классу функции указатель this позволяет компилятору разобраться, к какому параметру относится сообщение. Снятие неоднозначности в теле принадлежащей классу функции между одинаковыми именами формального параметра и компонента класса можно осуществить и без указателя this. Гораздо чаще применяют операцию изменения видимости: имя_класса : : имя_компонента.
Очень удобен указатель this, при необходимости задать компонентной функции адрес определенного объекта класса. Например, при организации списков, звеньями которого должны быть объекты класса.
Ниже приведён пример класса, объекты которого формируют двухсвязный список с использованием указателя this.
class member // Member.h
{ static member *last_memb;
member *prev; member *next; char bukva;
public :
member(char cc) { bukva=cc; } // конструктор
void add (void);
static void reprint (void);};
#include <iostream.h> //Member.cpp
#include <stdio.h> #include “member.h”
void member : : add(void) //добавление списка
{ if (last_memb==NULL ) this->prev=NULL;
else {last_memb->next=this; prev=last_memb;}
last_memb=this; this ->next=NULL;}
void member : : reprint (void)
{ member *uk; uk=last_memb;
if (uk==NULL) { cout<<“\ n Список пуст!”; return ; }
else cout<<“\ n Содержимое списка: \ n”;
while (uk!=NULL) { cout<<uk->bukva<<‘\ t’; uk=uk->prev;}}
#include <iostream.h> //Spisok.cpp Основной модуль
#include “member.cpp”
member *member::last_memb=NULL;
Void main()
{ member A(‘a’); member B(‘b’); member C(‘c’); member D(‘d’);
member : : reprint()
A.add(); B.add(); C.add(); D.add();
member : : reprint();}
8 Друзья классов
Дружественной функцией класса называется функция, которая, не являясь его компонентой, имеет доступ к его защищенным и собственным компонентам. Она расширяет интерфейс класса. Для получения прав друга функция должна быть описана в теле класса со спецификатором friend.
#include <conio.h>
class charlocus
{ int x,y; char cc;
friend void friend_put (charlocus *, char);
public :
charlocus (int xi, int yi, char ci) { x=xi; y=yi; cc=ci;} //конструктор
void display (void) { gotoxy(x, y); putch (cc); }
};
void friend_put (charlocus *p, char c) { p->cc=c; }
void main (void)
{ charlocus D(20,4,’d’); charlocus S (10,10,’s’)’; clrscr();
D.display(); getch(); S.display(); getch(); friend_put (&D,’*’);
D.display(); getch(); friend_put (&S,’#’); S.display(); getch();
}
Дружественные функции при вызове не получают указателя this. Объекты классов должны передаваться другим функциям явно через аппарат параметров. Вызывать дружественные функции как компонентные нельзя, так как они не являются компонентами классов.
Дружественная функция:
не может быть компонентной функцией того класса, по отношению к которому, она дружественна;
может быть глобальной функцией
class CL { friend int f1(. . . ); . . . };
int f1 (. . .) {тело функции }
может быть компонентной функцией другого, ранее определенного класса: class CLASS { . . . char f2(. . .); . . . };
class CL { . . . friend char CLASS : : f2(. . .); . . . };
может быть дружественной по отношению к нескольким классам:
class CL2;
class CL1 {friend void ff(CL1, CL2); . . . };
class CL2 {friend void ff(CL1, CL2); . . . };
void ff( . . . ) { тело функции }
Использование механизма дружественных функций упрощает интерфейс между классами. Дружественная функция позволяет получить доступ к собственным или защищенным компонентам сразу нескольких классов. Таким образом, из классов можно убрать компонентные функции, предназначенные только для доступа к “скрытым” компонентам.
Дружественная функция двух классов “точка на плоскости” и “прямая на плоскости” приведена в примере. Уравнение прямой Ах+Вх+С=0. Дружественная функция определяет уклонение заданой точки от заданой прямой. Выражение вычисления уклонения А*а + В*в + С, где а и в - координаты точки.
#include <iostream.h>
class line; //предварительное описание
class point
{ float x, y;
public :
point (float xn=0, float yn=0) { x=xn; y=yn; }
friend float uclon (point, line);
};
class line
{ float A, B, C;
public :
line (float a, float b, float c) { A=a; B=b; C=c; }
friend float uclon (point, line);
};
float uclon (point p, line l) { return l.A*p.x+l.B*p.y+l.C; }
void main (void)
{ point p(16.0, 12.3); line l (10.0, -42.3, 24.0);
cout<<“\ n Уклонение точки Р от прямой L:”<<uclon(p, l);
}
Класс может быть дружественным другому классу. Это означает, что все компонентные функции класса являются дружественными для другого класса. Дружественный класс определяется вне тела класса “предоставляющего дружбу“.
class x2 {friend class x1; . . . };
class x1 { . . . void f1(. . .); void f2(. . .); . . . };
Все компоненты класса доступны в дружественном классе.
Итак:
На описание friend не влияют спецификаторы public, protected или union.
Описания friend невзаимны: если А объявляет В другом, то это не означает, что А является другом для В.
Дружественность не наследуется: если А объявляет В другом, классы, производные от В, не будут автоматически получать доступ к элементам А.
Дружественность не является переходным свойством: если А объявляет В другом, классы, производные от А, не будут автоматически признавать дружественность В.
