- •6Vpj7-h3cxh-hbtpt-x4t74-3yvy7
- •Оглавление
- •Предисловие
- •Введение
- •1.1. Понятие класса и объекта. Инкапсуляция
- •1.2. Определение классов. Компоненты. Доступность
- •Class_key /*class_id*/ { /*members_list*/ };
- •Value_type class_id::function_id(parameters) {statements}
- •CPoint point1(100,70); // локальный объект
- •Static cPoint point3(50,120); // статический объект
- •Class_id(parameters) /*:initializer_list*/ {/*statements*/}
- •CString(const char *);
- •Delete[] __thematrix;
- •1.4. Обращение к компонентам объектов
- •1.5. Статические и нестатические компоненты классов
- •1.7. Указатель this
- •В опросы для самопроверки
- •2. Механизм наследования. Полиморфизм
- •2.1. Формы наследования. Базовые и производные классы
- •Class_key class_id: inheritance_specifier base_class_id {member_list};
- •2.3. Абстрактные классы
- •2.4. Множественное наследование и виртуальные классы
- •2.5. Преобразование динамических типов. Динамическая идентификация типов
- •Catch ( std::bad_cast & ) { // обработка исключения
- •Return 0;
- •Вопросы для самопроверки
- •3. Дружественные функции и классы
- •3.1. Дружественные функции
- •3.2. Дружественные классы
- •Вопросы для самопроверки
- •4. Механизм вложения
- •4.1. Вложенные классы
- •4.2. Локальные классы
- •Вопросы для самопроверки
- •5. Объектная модель и шаблоны
- •5.1. Определение, описание и инстанцирование шаблонов
- •::Function_id(function_parameter_list) { statements }
- •5.2. Параметры и аргументы шаблонов
- •Class identifier typename identifier
- •// Key, Data – параметры-типы (типы ключа и данных отображения)
- •// Container – контейнер, где содержится информация отображения class сMap {
- •Class MyTemplate
- •Int array[10]; struct Structure { int m; static int sm; } str;
- •5.3. Шаблоны компонентных функций
- •Value_type function_template_id(function_parameter_list) { statements }
- •::Function_template_id(function_parameter_list) { statements }
- •5.4. Специализация шаблонов
- •Вопросы для самопроверки
- •6. Перегрузка операций
- •Value_type operator @ (parameter_list);
- •Value_type operator @ (parameter_list) { statements }
- •Return fail();
- •6.3. Перегрузка бинарных операций
- •Value_type operator @ (parameter); // компонентная функция
- •Value_type operator @ (parameter, parameter); // глобальная функция friend value_type operator @ (parameter, parameter); // дружественная функция
- •Return *this;
- •Return *this;
- •/* Присваиваем собственные данные класса d */
- •6.4. Перегрузка операций управления памятью
- •Typedef void (*new_handler) ();
- •Extern new_handler set_new_handler( new_handler new_p );
- •Void operator delete(void * memory) {
- •... // Специальная обработка пользователя ::operator delete(memory); // освободить память
- •Вопросы для самопроверки
- •7. Механизм исключений
- •Throw expression
- •7.3. Специальные средства поддержки механизма исключений
- •Unexpected_function set_unexpected(unexpected_function func_name);
- •Typedef void (* unexpected_function) ();
- •Extern char * __throwExceptionName; extern char * __throwFileName; extern unsigned __throwLineNumber;
- •Вопросы для самопроверки
- •8. Подсчет ссылок
- •8.1. Назначение механизма подсчета ссылок
- •8.2. Контекстно-независимая модель счетчика ссылок
- •8.4. Внедрение подсчета ссылок в существующий класс
- •Вопросы для самопроверки
- •9. Стандартная библиотека шаблонов (stl)
- •9.1. Назначение и архитектура stl
- •9.2. Последовательные контейнеры
- •Class vector {
- •// Определение итераторов
- •Sort(first,last); // сортировка вектора в диапазоне итераторов
- •Ifstream ifile ("example.In"); ofstream ofile ("example.Out");
- •OutputIterator copy(
- •InputIterator first, InputIterator last, OutputIterator result );
- •// Заполнение списка
- •Operator- (int)
- •Operator- (random access iterator) operator[] (int)
- •InputIterator find(InputIterator first, InputIterator last, const t & value);
- •InputIterator find(InputIterator first, InputIterator last, const t & value)
- •Return first;
- •OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
- •Return result;
- •OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op)
- •Return result;
- •Void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
- •__Quick_sort_loop(first, last, comp); __final_insertion_sort(first, last, comp);
- •T accumulate(InputIterator first, InputIterator last, t init, Function f);
- •V.Push_back(2); V.Push_back(5);
- •9.5. Функторы
- •T operator()(const t & X) const { return -X; }
- •9.7. Адаптеры
- •S1.Push(1); s1.Push(5);
- •// Записать в вектор числа 1 2 3 4
- •// Сортировать по неубыванию
- •// Записать в вектор числа 4 6 10 3 13 2
- •Вопросы для самопроверки
- •Заключение
- •Библиографический Список
- •6Vpj7-h3cxh-hbtpt-x4t74-3yvy7
Вопросы для самопроверки
Какие функции принято называть дружественными?
Как описать и определить дружественную функцию?
Опишите случаи, когда только механизм дружественных функций позволяет правильно реализовать требуемую функциональность.
В каком случае при вызове дружественной функции можно использовать операции ‘.’, ‘–>’, ‘.*’, ‘–>*’ ? Поясните ответ.
Каким образом можно определить дружественную функцию к вложенному классу? Приведите пример.
Как дружественная функция получает доступ к компонентам объекта класса, предоставляющего «дружбу»?
Класс C объявлен дружественным к классу B, а класс B является дружественным к классу A. Как сделать класс C дружественным к классу A? Приведите эскиз кода.
Можно ли сделать некоторый класс дружественным к иерархии классов? Если можно, то как? Поясните ответ примером.
Имеется класс class C { class A {}; class B {}; }; Как обеспечить неограниченный доступ классов C::A и C::B друг к другу?
Как можно сделать функцию, дружественную по отношению к иерархии классов, виртуальной к этой иерархии? Приведите фрагмент кода.
Каким образом можно имитировать «наследование» дружественности функций в классовых иерархиях? Приведите фрагмент кода.
Задачи
Разработать класс CSegment, представляющий отрезки на плоскости, а также класс CSquare, описывающий квадраты. Квадрат реализовать на основе четырех отрезков. При этом для обеспечения эффективности использовать отношение дружественности между классами CSquare и CSegment.
Определить класс CSheet, описывающий лист бумаги, на котором можно делать заметки. Также разработать класс CNotebook, отображающий свойства виртуальной записной книжки. Для реализации последнего использовать функциональность класса CSheet. Для обеспечения эффективности установить отношение дружественности между классами CSheet и CNotebook.
4. Механизм вложения
Любой класс в качестве компонента может содержать другой класс. Такое отношение, называемое отношением вложенности, обычно используется тогда, когда один класс (объемлющий) реализуется посредством другого (вложенного). Примером является класс, представляющий квадраты на плоскости (объемлющий), и класс, описывающий отрезки (вложенный), посредством которого можно реализовать класс квадратов (см. задачу 1 из главы 3). Еще один пример. Объемлющим классом является класс, описывающий матрицы. Вложенный – класс, описывающий одномерные массивы. Одномерный массив может представлять строку объекта-матрицы. Соответственно, компоненты такого массива могут использоваться матрицей для реализации ее функциональности (так, одномерный массив может включать функцию для суммирования всех элементов; в матрице эта функция будет суммировать элементы строки).
4.1. Вложенные классы
Вложенный класс можно определить непосредственно в объемлющем классе или за его пределами, но в том же пространстве имен. Его функции можно определять как внутри класса, так и за его пределами, в пространстве имен объемлющего класса. А его статические компоненты определяются только за пределами объемлющего класса. Внешнее определение вложенного класса и его компонент должно включать полную квалификацию имен.
Представленный ниже пример иллюстрирует возможные способы определения вложенных классов и их компонент.
Пример
class CEnclosing { // определение объемлющего класса
public:
class CNested1; // объявление первого вложенного класса
class CNested2; // объявление второго вложенного класса
...
class CNested1 { // определение первого вложенного класса
public:
...
private:
static int __static_member;
};
};
// внешнее определение статического компонента
int CEnclosing::CNested1::__static_member = 1;
// внешнее определение второго вложенного класса
class CEnclosing::CNested2 {
public:
void SomeFunction1();
void SomeFunction2() { // внутреннее определение функции
...
}
...
};
// внешнее определение функции второго вложенного класса
void CEnclosing::CNested2::SomeFunction1() { /* ... */ }
Особый интерес при работе с вложенными классами представляет взаимная доступность компонент объемлющего и вложенного классов. Компоненты вложенного класса могут иметь доступ только к открытым компонентам объемлющего класса. Справедливо и обратное: компоненты объемлющего класса могут иметь доступ только к открытым компонентам вложенного класса. Из указанных открытых компонент (как объемлющего, так и вложенного классов) непосредственно доступны только статические компоненты, имена типов и константы перечислений. Доступ к другим открытым компонентам требует указания объекта объемлющего / вложенного класса. Доступ к закрытым и защищенным компонентам возможен только при условии дружественности объемлющего и вложенного классов (дружественность может быть как односторонней, так и взаимной).
Пример, который приведен ниже, вряд ли можно считать практически значимым фрагментом кода, но он тем не менее хорошо поясняет все описанное в предыдущем абзаце.
Пример
int x, y;
class CEnclosing {
public:
int x;
static int s;
enum { const1 = 1, const2 = 2 };
class CInner {
public:
void f(int i) {
x = i; // ошибка, неясно к какому объекту относится x
s = i; // нормально, инициализация статического компонента
::x = i; // нормально, доступ к глобальным переменным
y = ::x;
// нормально, работаем с элементами перечисления
y = const1 + const2;
}
void g(CEnclosing * p, int i) {
p->x = i; // нормально, работаем с объектом *p
p->h(1); // ошибка, функция h недоступна
}
private:
static int q;
friend class CEnclosing;
};
protected:
void h(int i) {
CInner::q = i;
// нормально, компонент q доступен в силу дружественности
}
};
Вложенный класс, в принципе, является обычным классом; он просто локализован в пространстве имен объемлющего класса. Соответственно, он может быть базовым и/или производным классом. И еще одна интересная особенность. Интерфейс вложенного класса всегда включается в интерфейс объемлющего класса, т.е. все public-компоненты вложенного класса остаются открытыми независимо от того, в какой части объемлющего класса определен вложенный класс.