
- •1.Объявление и определение класса.
- •3. Дружественные функции.
- •4. Пеpегpузка опеpаций ( синтаксис operator)
- •5. Статические компоненты класса.
- •7. Иерархия классов ( последовательность работы конструкторов и деструкторов )
- •8. Доступ к наследуемым компонентам
- •9. Виртуальные функции (когда применяются, форма вызова)
- •10 . Шаблоны ( пример template)
- •15 Преобразование типов данных.
- •17 Ввод-вывод в файл. Сохранение объектов в файле.
- •18 Обработка исключений (блоки try, throw, catch)
- •Примеры обработки исключительных ситуаций
- •20. Паттерны и их классификация. Принцип классификации паттернов проектирования
- •Паттерны проектирования классов/обьектов
- •21. Абстрактная фабрика.
- •22. Классификация типов данных. Система типов
- •Oбщий взгляд
- •Класс String
- •Объявление строк. Конструкторы класса string
- •Операции над строками
- •Цикл foreach
- •Наследование
- •Добавление полей потомком
- •Конструкторы родителей и потомков
- •Интерфейсы
- •Две стратегии реализации интерфейса
- •Преобразование к классу интерфейса
3. Дружественные функции.
Друзьями класса называются функции, не являющиеся компонентами класса, но имеющие доступ к закрытой его части. Такие функции объявляются в интерфейсе класса в следующем виде:
friend тип имя (параметры);
Дружественные функции рекомендуется использовать в следующих случаях:
при необходимости упростить форму обращения к данным класса: не будучи компонентом класса, дружественная функция не требует соответствующей формы вызова. Например, для класса Complex можно определить функции getR и getI как дружественные:
friend double getR( Сomplex a){ return a.re;} friend double getI( Сomplex a){ return a.im;}
Обращение к ним следующее:
cin>>getR(m2); cin>>getI(m2);
при необходимости использовать методы одного класса для обработки закрытых данных другого класса. Объявление функции производится по следующей схеме:
class Y {
...
void fy (){...} //Определение функции класса Y
...
};
class X {
...
void fx(){...}
friend void Y::fy();// Объявление функции fy дружественной классу X
...
};
Пример
#include <iostream.h>
class X; // Объявление класса Х
class Y {
int a;
public:
Y(int n):a(n){}; // Форма записи аналогична {a=n;}
void display(X* pX); //Функция-компонент класса Y
};
class X{
int a;
public:
X(int n):a(n){};
friend void Y::display(X* pX); .// Функция объявляется дружественной классу Х и
}; // имеет доступ к полю а как класса Х, так и класса Y
void Y::display(X* pX){
cout<<pX->a<<'\t'<<a<<endl;
}
void main(){
X mx(100);
Y my(200);
my.display(&mx);
}
Результат на дисплее: 100 200
Все функции одного класса могут быть дружественными другому классу.
4. Пеpегpузка опеpаций ( синтаксис operator)
Если действие какой-либо операции расширено на операнды, тип которых отличается от типа операндов, для которых создавалась операция, или вообще знак операции не соответствует общепринятому смыслу операции, то говорят, что операция перегружена. Например, стандартная операция сложения может быть перегружена для строковых данных, комплексных чисел и т.п. Естественно, что перегруженность сохраняет смысл только для данных того класса, в котором она произведена. Перегрузка операций производится с помощью специальной функции operator согласно следующей форме:
тип operator знак_опеpации(типы аpгументов){... }.
Перегруженная операция может быть определена как компонент класса; в этом случае она имеет один параметр или вообще не имеет параметров. У дружественной перегруженной операции может быть один или два параметра. Поэтому бинарные операции следует перегружать как дружественные.
Пpимеp для класса Сomplex:
class Complex { double re,im; public: ............. friend Complex operator+(Complex, Complex); }; Complex operator+( Complex l, Complex m) { return Complex (l.re+m.re, l.im + m.im);} main(){ Complex m1(5,2),m2(6,6),m3(0); m3=m1+m2; return 0; }
Операция ‘+‘ вне класса Complex действует как обычно.
(Функция operator+(a,b) позволяет использовать краткую форму записи a+b. Мы могли бы без перегрузки записать m3=operator+(m1,m2); это относится и к другим операциям)
Перегружаться могут практически все операции (исключение – оператор принадлежности ::, операторы . .* ?: sizeof и символ #). При этом функция operator не изменяет приоритеты операций и число операндов, определенных в языке.
Функция operator для переопределения бинарных операций может быть описана как функция-компонент класса с одним аргументом (например, для операции сложения a.operator+(b) ) или как дружественная функция с двумя аргументами operator+(a,b) ); унарная операция – как функция-компонент без аргументов или как дружественная функция с одним аргументом. Четыре функции operator=, operator[], operator() и operator-> должны быть нестатическими компонентами-функциями класса.
Все перегруженные операции, кроме ‘=’ наследуются. Относительно последней нужно отметить, что по умолчанию при ее использовании выполняется почленное копирование одного объекта в другой; например, если для класса String запишем:
String s1(10), s2(10); s1=s2;
то в результате операции присваивания s1 будет иметь тот же указатель, что и s2; при изменении s2 изменяется и s1. Поэтому операцию присваивания целесообразно перегружать с выделением памяти для первого массива по типу:
X&x:: operator=(X&)
Для класса String можно записать:
void String::operator=(String& a) { if (this==&a) return; //для предотвращения s1=s1; delete charPtr; //чистка памяти
length=a.length; charPtr= new char[length+1]; strcpy(charPtr,a.charPtr); }
Перегруженные функции имеют тот же смысл, что и операции: функция с одним и тем же именем работает по-pазному с различными типами аргументов. Примером является набор конструкторов в классе String.
Функции new и delete перегружаются c помощью функции operator следующим образом:
void* operator new(size_t t [,список аргументов]),
где size_t – первый и единственный обязательный аргумент.
Например, перегрузка
void* operator new(size_t t, int n){ return new char[t*n]; }
позволяет добавить к стандартной функции new еще один аргумент – количество блоков памяти размером size_t каждый. Предположим, что функция вызывается с n=5 и t=double:
double *d=new(5) double;
Значение t в теле функции станет равным sizeof(double)=8 (для персональных компьютеров); в результате под переменную будет выделено 5*8=40 байтов памяти.