Class pObj
{
public:
static void * operator new(size_t size);
//...
private:
union
{
Obj *p; // Вказівка на об'єкт
pObj *next; // Вказівка на наступний вільний осередок
};
static const int BLOCK_SIZE; // Розмір блоку
// Заголовок списку вільних осередків
static pObj *headOfFree;
};
void * pObj::operator new(size_t size)
{
// Перенаправити запити невірної кількості пам'яті
// стандартній операції new:
if (size != sizeof(pObj)) return ::operator new(size);
pObj*p = headOfFree; //Вказівка на перший вільний осередок
// Перемістити вказівку списку вільних осередків:
if (p) headOfFree = p->next;
// Якщо вільної пам'яті немає. виділяємо черговий блок:
else
{
pObj *newblock = static_cast<pObj*>
(::operator new(BLOCK_SIZE * sizeof(pObj)));
// Всі осередки вільні, окрім першого (він буде
// зайнятий), зв'язуємо їх:
for(int i=1;i<BLOCK_SIZE;i++)
newblock[i].next = &newblock[i + 1];
newblock[BLOCK_SIZE-1].next = 0;
// Встановлюємо початок списку вільних осередків:
headOfFree = &newblock[1];
p = newblock;
}
return p; // Повертаємо вказівку на виділену пам'ять
}
Перевантажений оператор new успадковується, тому вона викликається для похідних об'єктів. Якщо їх розмір не відповідає розміру базового (а так, швидше за все, і є), це може викликати проблеми. Щоб їх уникнути, на початку операції перевіряється відповідність розмірів. Якщо розмір об'єкту не дорівнює тому, для якого перевантажений оператор new, запит на виділення пам'яті передається стандартному оператору new.
У програмі, що використовує клас pObj, має бути присутньою ініціалізація його статичних полів:
pObj *pObj::headOfFree; // Встановлюється в 0 за умовчанням
const int pObj::BLOCK_SIZE = 1024;
Як видно з цього прикладу, окрім економії пам'яті досягається ще і висока швидкодія, адже в більшості випадків виділення пам'яті зводиться до декількох простих операторів.
Природно, що якщо оператор new перевантажений, те ж саме повинно бути виконано і для оператору delete (наприклад, в нашому випадку стандартний оператор delete не знайде на початку об'єкту вірної інформації про його розміри, що приведе до невизначеної поведінки програми).
У розглянутому прикладі оператор delete повинен додавати звільнений елемент пам'яті до списку вільних осередків:
void pObj::operator delete(void* ObjToDie, size_t size)
{
if (ObjToDie == 0) return;
if (size != sizeof(pObj))
{
::operator delete(ObjToDie);
return;
}
pObj *p = static_cast<p0bj*>(0bjToDie);
p->next = headOfFree;
headOfFree = p;
}
У операторі delete виконана перевірка відповідності розмірів об'єктів, аналогічна приведеною в операторі new.
5.5 Перевантаження оператору приведення типу
Можна визначити функції-оператор, які здійснюватимуть перетворення об'єкту класу до іншого типу. Формат:
operator ім’я нового типу ();
Тип значення, яке повертається і параметри вказувати не потрібно. Можна визначати віртуальні функції перетворення типу.
Приклад:
monstr::operator int() {return health;}
...
monstr Vasia;
cout << int(Vasia);
5.6 Перевантаження оператору виклику функції
Клас, в якому визначений оператор виклику функції, називається функціональним. Від такого класу не вимагається наявності інших полів і методів:
Дата добавления: 2014-12-26; просмотров: 841;