
- •Объектно-ориентированное программирование:
- •Содержание
- •Новый тип данных – класс
- •1.2. Доступность компонентов класса
- •1.3. Конструктор и деструктор
- •1.4. Компоненты-данные и компоненты-функции
- •1.4.1. Данные – члены класса
- •1.4.2. Функции – члены класса
- •1.4.3. Константные компоненты-функции
- •1.4.4. Статические члены класса
- •Указатели на компоненты класса
- •1.5.1. Указатели на компоненты-данные
- •1.5.2.Указатели на компоненты-функции
- •1.6. Указатель this
- •1.7. Друзья классов
- •7.1. Дружественная функция
- •1.7.2. Дружественный класс
- •1.8. Определение классов и методов классов
- •2. Наследование
- •2.1. Определение производного класса
- •2.2. Конструкторы и деструкторы производных классов
- •2.3. Виртуальные функции
- •2.4. Абстрактные классы
- •2.5. Включение объектов
- •2.6. Включение и наследование
- •2.7. Множественное наследование
- •2.8. Локальные и вложенные классы
- •2.9. Пример программы для Microsoft Visual Studio
- •2.10. Упражнения
- •3. Перегрузка операций
- •3.1. Перегрузка унарных операций
- •3.2. Перегрузка бинарных операций
- •3.4. Перегрузка операции вызова функции
- •3.5. Перегрузка операции присваивания
- •3.6. Перегрузка операции new
- •3.7. Перегрузка операции delete.
- •3.8. Основные правила перегрузки операций
- •3.9. Примеры программ
- •4. Шаблоны функций и классов
- •4.1. Шаблоны функций
- •4.2. Шаблоны классов
- •4.3. Компонентные функции параметризованных классов
- •4.4. Примеры программ.
- •5. Обработка исключительных ситуаций
- •5.2. Получение дополнительной информации об исключении
- •5.3. Определение типа исключения
- •5.4. Иерархия исключений
- •5.5. Спецификация функций, обрабатывающих исключения
- •6. Потоковые классы
- •6.1. Библиотека потоковых классов
- •6.3. Стандартные потоки ввода-вывода
- •6.4. Форматирование
- •6.5. Манипуляторы
- •6.6. Ввод-вывод объектов пользовательских классов
- •6.7. Определение пользовательских манипуляторов
- •6.8. Пользовательские манипуляторы с параметрами
- •6.9. Использование макросов для создания манипуляторов
- •6.10. Состояние потока
- •6.11. Неформатированный ввод-вывод
- •6.12. Файловый ввод-вывод
- •7.1. Пространство имен
- •7.2. Динамическая идентификация типов
- •7.3. Безопасное приведение типа
- •8. Стандартная библиотека шаблонов
- •8.1. Введение в stl
- •Парадигму обобщенного программирования можно сформулировать следующим образом:
- •8.2. Итераторы
- •8.3. Классы-контейнеры
- •Iterator find(const key_type&k)
- •Iterator lower_bound(const key_type&k)
- •Iterator upper_bound(const key_type&k)
- •8.4. Контейнер vector
- •8.5. Многомерные массивы
- •8.6. Ассоциативные контейнеры
- •8.7. Объекты-функции
- •8.8. Алгоритмы
- •I. Немодифицирующие операции
- •II. Модифицирующие операции
- •III. Сортировка
- •IV. Работа с множествами
- •V. Минимумы и максимумы
- •VI. Перестановки
2.8. Локальные и вложенные классы
Класс может быть объявлен внутри блока, например внутри определения функции. Такой класс называется локальным. Локализация класса предполагает недоступность его компонентов вне области определения класса (вне блока).
Локальный класс не может иметь статических данных, т.к. компоненты локального класса не могут быть определены вне текста класса.
Внутри локального класса разрешено использовать из объемлющей его области только имена типов, статические (static) переменные, внешние (extern) переменные, внешние функции и элементы перечислений. Из того, что запрещено, важно отметить переменные автоматической памяти. Существует еще одно важное ограничение для локальных классов – их компонентные функции могут быть только inline.
Внутри класса разрешается определять типы, следовательно, один класс может быть описан внутри другого. Такой класс называется вложенным. Вложенный класс является локальным для класса, в рамках которого он описан, и на него рапространяются те правила использования локального класса, о которых говорилось выше. Следует особо сказать, что вложенный класс не имеет никакого особого права доступа к членам охватывающего класса, то есть он может обращаться к ним только через объект типа этого класса (так же, как и охватывающий класс не имеет каких-либо особых прав доступа к вложенному классу).
Пример 2.8.1.
int i;
class global{
static int n;
public:
int i;
static float f;
class intern{
void func(global& glob)
{i=3; // Ошибка: используется имя нестатического данного
// из охватывающего класса
f=3.5; // Правильно: f-статическая функция
::i=3; // Правильно: i-внешняя(по отношению к классу)
// переменная
glob.i=3;// Правильно: обращение к членам охватывающего
// класса через объект этого класса
n=3; // Ошибка: обращение к private-члену охватывающего
//класса
} }; };
Пример 2.8.2. Класс «ПРЯМОУГОЛЬНИК».
Определим класс «прямоугольник». Внутри этого класса определим класс как вложенный класс “отрезок”. Прямоугольник будет строится из отрезков.
#include <conio.h>
#include <graphics.h>
// точка
class point{
protected:
int x,y;
public:
point(int x1=0,int y1=0):x(x1),y(y1){}
int& getx(){return x;}
int& gety(){return y;}
};
// прямоугольник
class rect{
// вложенный клас “отрезок”
class segment{
point a,b; //начало и конец отрезка
public:
segment(point a1=point(0,0),point b1=point(0,0))
{a.getx()=a1.getx();
a.gety()=a1.gety();
b.getx()=b1.getx();
b.gety()=b1.gety();}
point& beg(){return a;}
point& end(){return b;}
void Show() //показать отрезок
{line(a.getx(),a.gety(),b.getx(),b.gety());}
}; //конец определения класса segment
segment ab,bc,cd,da; //стороны прямоугольника
public:
rect(point c1=point(0,0),int d1=0,int d2=0)
{point a,b,c,d; //координаты вершин
a.getx()=c1.getx();
a.gety()=c1.gety();
b.getx()=c1.getx()+d1;
b.gety()=c1.gety();
c.getx()=c1.getx()+d1;
c.gety()=c1.gety()+d2;
d.getx()=c1.getx();
d.gety()=c1.gety()+d2;
//граничные точки отрезков
ab.beg()=a; ab.end()=b;
bc.beg()=b; bc.end()=c;
cd.beg()=c; cd.end()=d;
da.beg()=d; da.end()=a;}
void Show() //пока прямоугольник
{ab.Show();
bc.Show();
cd.Show();
da.Show();}
}; //конец определения класса rect
void main()
{int dr=DETECT,mod;
initgraph(&dr,&mod,"C:\\tc3\\bgi");
point p1(120,80);
point p2(250,240);
rect A(p1,80,30);
rect B(p2,100,200);
A.Show();getch();
B.Show();getch();
closegraph();
}
Используя эту методику, можно определить любую геометрическую фигуру, состоящую из отрезков прямых.
Пример 2.8.3. Класс «СТРОКА».
Класс string хранит строку в виде массива символов с завершающим нулем в стиле Си и использует механизм подсчета ссылок для минимизации операций копирования.
Класс string пользуется тремя вспомогательными классами:
srep, который позволяет разделять действительное представление между несколькими объектами типа string с одинаковыми значениями;
range–для генерации исключения в случае выхода за пределы диапазона;
cref – для реализации операции индексирования, который различает операции чтения и записи.
class string{
struct srep;
srep* rep;
public:
class cref; //ссылка на char
class range{};
//…
};
Так же, как и другие члены, вложенный класс может быть объявлен в самом классе, а определен позднее.
struct string::srep{
char *s; //указатель на элементы
int sz; //количество символов
int n; //количество обращений
srep(const char *p)
{n=1;
sz=strlen(p);
s=new char[sz+1];
strcpy(s,p);
}
~srep(){delete[]s;}
srep *get_copy() //сделать копию,если необходимо
{if(n==1)return this;
n--;
return new srep(s);}
void assign(const char *p)
{if(strlen(p)!=sz){delete[]s;
sz=strlen(p);
s=new char[sz+1];}
strcpy(s,p);}
private: //предохраняет от копирования
sper(const srep&);
srep& operator=(const srep&);
}