- •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
8.4. Внедрение подсчета ссылок в существующий класс
Выше, при внедрении подсчета ссылок в класс, у нас был доступ к файлу с определением этого класса, но как включить подсчет ссылок в класс, который мы не можем изменять (например, класс из библиотеки)? Хороший вариант – создать собственный класс в качестве «обертки» (wrapper) для этого класса и внедрить подсчет ссылок в новый класс. Этот подход является весьма гибким и характеризуется прозрачностью для пользователя.
Ниже на примере показано, как внедрить подсчет ссылок в существующий класс на основе описанного подхода. Исходный класс описывает векторы с компонентами логического типа. Подсчет ссылок инкапсулируется в классе RefCounter, который мы уже видели выше.
Вот определение исходного класса векторов (возможно, в чем-то оно не эффективно, но его достаточно для нашей задачи):
class CBitVector {
public:
// конструктор
explicit CBitVector(size_t len):
_len(len > 0 ? len : 1), _items(new bool[_len]) { ; }
// копирующий конструктор
CBitVector(const CBitVector &);
// деструктор
virtual ~CBitVector();
// присваивание
CBitVector & operator = (const CBitVector &);
// ввод вектора из потока
friend istream & operator >> (istream &, CBitVector &);
// вывод вектора в поток
friend ostream & operator << (ostream &, const CBitVector &);
// индексация
bool & operator [] (size_t);
bool operator [] (size_t) const;
// длина
size_t GetLength() const { return _len; }
protected:
size_t _len; // длина
bool * _items; // элементы
}; /* CBitVector */
...
// реализация функций принципиального значения не имеет
...
Вот определение нашего класса-обертки:
class CBitVectorW {
public:
// конструктор
CBitVectorW(size_t len):
__pvaluesimulator(new CValueSimulator(len)) { ; }
// конструктор копирования
CBitVectorW(const CBitVectorW &);
// деструктор
~CBitVectorW();
// присваивание
CBitVectorW & operator = (const CBitVectorW &);
// ввод-вывод
friend istream & operator >> (istream &, CBitVectorW &);
friend ostream & operator << (ostream &, const CBitVectorW &);
// индексация
bool & operator [] (size_t i);
bool operator [] (size_t i) const;
private:
// класс – имитатор значения вектора
class CValueSimulator: public CRefCounter {
public:
// конструктор
CValueSimulator(size_t len):
__prealvector(new CBitVector(len)) { ; }
CValueSimulator(const CValueSimulator & o):
__prealvector(new CBitVector(*o.__prealvector)) { ; }
~CValueSimulator() { delete __prealvector; }
// связь с «реальным» вектором
CBitVector * __prealvector;
}; /* CValueSimulator */
CValueSimulator * __pvaluesimulator; // связь со значением
// копирование (для устранения дублирования кода)
void __MakeCopy(const CBitVectorW &);
}; /* CBitVectorW */
// ----- реализация функций -----
// индексация
inline bool CBitVectorW::operator [] (size_t i) const {
// проверка индекса
i = i >= this->__pvaluesimulator->__prealvector->GetLength() ? 0 : i;
// доступ к «реальному» вектору
return (*this->__pvaluesimulator->__prealvector)[i];
}
// конструктор копирования
inline CBitVectorW::CBitVectorW(const CBitVectorW & o) {
__MakeCopy(o);
}
// деструктор
inline CBitVectorW::~CBitVectorW() {
this->__pvaluesimulator->RemoveRef();
}
// вывод
inline ostream & operator << (ostream & str, const CBitVectorW & o) {
// выводится замещаемый вектор
return str << *o.__pvaluesimulator->__prealvector;
}
// ввод
istream & operator >> (istream & str, CBitVectorW & o) {
if (o.__pvaluesimulator -> IsShared()) {
// попытка изменить разделяемое значение
o.__pvaluesimulator -> RemoveRef();
// создаем копию значения
o.__pvaluesimulator =
new CBitVectorW::CValueSimulator(*o.__pvaluesimulator);
}
return str >> *o.__pvaluesimulator->__prealvector;
}
// копирование
void CBitVectorW::__MakeCopy(const CBitVectorW & o) {
if (o.__pvaluesimulator -> CanBeShared() == false)
{ // значение нельзя использовать совместно
this->__pvaluesimulator =
new CBitVectorW::CValueSimulator(*o.__pvaluesimulator);
}
else {
// значение можно использовать совместно
this -> __pvaluesimulator = o.__pvaluesimulator;
this -> __pvaluesimulator -> AddRef();
}
}
// присваивание
CBitVectorW & CBitVectorW::operator = (const CBitVectorW & o) {
if (this == &o) return *this;
this -> __pvaluesimulator -> RemoveRef();
__MakeCopy(o);
return *this;
}
// индексация (для не-const-объекта)
bool & CBitVectorW::operator [] (size_t i) {
if ( i >= this->__pvaluesimulator->__prealvector->GetLength() )
throw std::range_error("Incorrect index");
if ( this -> __pvaluesimulator -> IsShared() ) {
// для разделяемого значения создаем копию
this -> __pvaluesimulator -> RemoveRef();
this -> __pvaluesimulator =
new CBitVectorW::CValueSimulator(*(*this).__pvaluesimulator);
}
// запрещаем совместное использование
this -> __pvaluesimulator -> MakeUnshareable();
// обращаемся к реальному вектору
return (*this->__pvaluesimulator->__prealvector)[i];
}
Ниже показано применение класса-обертки в программе. Из приведенного фрагмента кода видно, что работа с оберткой столь же удобна, как и использование «реального» класса, однако теперь у нас есть новая функциональность:
...
CBitVectorW v(5), w(4);
cin >> v >> w;
CBitVectorW z(v); // z и v разделяют значение
cout << endl << "S T E P - 1: " << endl;
cout << "v = " << v << "w = " << w << "z = " << z;
w = v; // теперь z, v, w разделяют одно значение
cout << endl << "S T E P - 2: " << endl;
cout << "v = " << v << "w = " << w << "z = " << z;
cin >> v; // для v создается копия
cout << endl << "S T E P - 3: " << endl;
cout << "v = " << v << "w = " << w << "z = " << z;
w = v = z; // z, v, w снова разделяют одно значение
cout << endl << "S T E P - 4: " << endl;
cout << "v = " << v << "w = " << w << "z = " << z;
w[0] = !w[0]; // w теперь имеет неразделяемое значение
cout << endl << "S T E P - 5: " << endl;
cout << "v = " << v << "w = " << w << "z = " << z;
bool * pbool = &v[0]; // и v имеет неразделяемое значение
*pbool = !*pbool;
cout << endl << "S T E P - 6: " << endl;
cout << "v = " << v << "w = " << w << "z = " << z;
...
Из кода и комментариев легко понять принцип включения подсчета ссылок в недоступный для изменения класс и применять его в общем случае. Более подробная информация о механизме подсчета ссылок содержится в книге [6].