UR.ANUS
Идиомы и стили С++
вернуться

Makhmutov Albert

Шрифт:

};

int main {

 Cthat* aThat = new Cthat;

 aThat-›doSomething;

 CPthat pthat(new Cthat);

 pthat-›doIt; // Вариант обращения через -›

 ((Cthat*)pthat)-›doIt ; //Вариант обращения через Cthat*

 delete aThat;

 return 0;

}

Что получилось: Имеем класс Cthat, который может иметь экземпляры, хотя и не имеет наполнения, и может исполнить пустую функцию. (Обратите внимание. Пустой объект имеет размер 1, и если добавить переменную char, то размер будет тот же. Экземпляры пустых объектов существуют, и они различаются.) Имеем класс объекта-указателя CPthat, в котором храним обычный указатель, но доступ к нему ограничиваем, и перегружаем для него операторы:

1. приведения типа Cthat

2. member selector – ›.

3. Операторы арифметики указателей. Я указал только один, сложение.

Идея ясная. Нужно переопределить все восемь, или не переопределять их вовсе. Вопрос в том, направлен ли Ваш указатель на массив, или нет. Во всяком случае, не спешите с этим. Да, и в Ваших плюсах скорее всего тип ptrdiff_t надо заменить на ptr_diff. Я просто дома на BC3.1 все проверяю.

Что здесь хорошего? Мы получили класс объектов-указателей, которые можно смело применять вместо настоящих. Деструктор ~CPthat уничтожает указуемый объект, поскольку сам по себе последний не имеет имени, и без своего указателя утрачивает идентичность. Проще говоря, останется в нашей памяти навечно, как герой. Ну можно конечно вызывать деструктор и явно, а что? Вот так:

pthat-›~Cthat;

Тогда удаление уберите из деструктора указателя.

Напоследок сделаем очевидный шаг - сделаем умный указатель параметризированным классом.

template ‹class T›

class SmartPointer {

private:

 T* tObj;

public:

 SmartPointer(T* _t=NULL):tObj(_t);

 ~SmartPointer{ if (tObj) delete tObj; }

 operator T*{ return tObj; }

 T* operator-›{ return tObj; }

};

Для интереса посмотрите, как сделан auto_ptr в STL.

Передохнем. Кофе. Джоггинг. Пиво. Сигарета. Нужное подчеркнуть, выпить, покурить.

Шаг 3 - Как это применять.

Берем код параметризированного класса.

template ‹class T›

class SmartPointer {

private:

 T* tObj;

public:

 SmartPointer(T* _t=NULL): tObj(_t);

 ~SmartPointer {if (tObj) delete tObj;}

 operator T*{return tObj;}

 T* operator-›{return tObj;}

};

1. Обработка обращения к NULL.

Заменяем реализацию оператора – › на:

T* operator-› {

 if (!tObj) {

cerr ‹‹ "NULL";

tObj = new T;

 }

 return tObj;

}

или

T* operator-› {

 if (!tObj) throw CError;

 return tObj;

};

Здесь CError класс исключения. Или втыкаем статический экземпляр-шпион.

private:

 T* tObj; // Это было;

 static T* spy; // Это добавлено

Ну и сам перегруженный оператор.

T* operator-›
{

 if (!tObj) return spy;

 return tObj;

};

Здесь нужно пояснить: spy совсем не обязательно класса T. Можно воткнуть производный, и переопределить его функции. Тогда он будет Вам докладывать о попытках обращения к NULL. Не забудьте его создать, инициализировать, и прицепить к указателю. А то вся идея на помойку. Вы пытаетесь отловить обращение к NULL, а там… NULL!!! "Матрицу" видели?

2. Отладка и трассировка.

  • Читать дальше
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • ...

UR.ANUS - русскоязычная библиотека для чтения онлайн. Здесь удобно открывать книги с телефона и ПК, возвращаться к сохраненной странице и держать любимые произведения под рукой. Материалы добавляются пользователями; если считаете, что ваши права нарушены, воспользуйтесь формой обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • support@anus.bid