Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 53 54 55 [ 56 ] 57 58 59 ... 120


класса. Настоящее копирование можно определить так:

void expr::copy(expression* s, int deep)

if (deep == 0) { копируем только члены *this = *s;

else { пройдемся по указателям: left = s->clone(1); right = s->clone(1); ...

Функция expr::clone() будет вызываться только для объектов типа expr (но не для производных от expr классов), поэтому можно просто разместить в ней и возвратить из нее объект типа expr, являющийся собственной копией:

expr* expr::clone(int deep)

expr* r = new expr(); строим стандартное выражение r->copy(this,deep); копируем *this в r return r;

Такую функцию clone() можно использовать для производных от expr классов, если в них не появляются члены-данные (а это как раз типичный случай):

class arithmetic : public expr { ...

новых членов- данных нет =>

можно использовать уже определенную функцию clone

С другой стороны, если добавлены члены-данные, то нужно определять собственную функцию clone():

class conditional : public expression { expr* cond; public:

inline void copy(cond* s, int deep = 0); expr* clone(int deep = 0); ...

Функции copy() и clone() определяются подобно своим двойникам из expression:

expr* conditional::clone(int deep)

conditional* r = new conditional(); r->copy(this,deep); return r;

void conditional::copy(expr* s, int deep)

if (deep == 0) { *this = *s;

else {

expr::copy(s,1); копируем часть expr cond = s->cond->clone(1);



Определение последней функции показывает отличие настоящего копирования в expr::copy() от полного размножения в expr::clone() (т.е. создания нового объекта и копирования в него). Простое копирование оказывается полезным для определения более сложных операций копирования и размножения. Различие между copy() и clone() эквивалентно различию между операцией присваивания и конструктором копирования ($$1 .4.2) и эквивалентно различию между функциями draw() и draw() ($$6.5.3). Отметим, что функция copy() не является виртуальной. Ей и не надо быть таковой, поскольку виртуальна вызывающая ее функция clone(). Очевидно, что простые операции копирования можно также определять как функции-подстановки.

6.7.2 Указание размещения

По умолчанию операция new создает указанный ей объект в свободной памяти. Как быть, если надо разместить объект в определенном месте? Этого можно добиться переопределением операции размещения. Рассмотрим простой класс:

class X {

...

public:

X(int);

Объект можно разместить в любом месте, если ввести в функцию размещения дополнительные параметры:

операция размещения в указанном месте: void* operator new(size t, void* p) { return p; }

и задав эти параметры для операции new следующим образом:

char buffer[sizeof(X)]; void f(int i)

X* p = new(buffer) X(i); разместить X в buffer ...

Функция operator new(), используемая операцией new, выбирается согласно правилам сопоставления параметров ($$R.13.2). Все функции operator new() должны иметь первым параметром size t. Задаваемый этим параметром размер неявно передается операцией new.

Определенная нами функция operator new() с задаваемым размещением является самой простой из функций подобного рода. Можно привести другой пример функции размещения, выделяющей память из некоторой заданной области:

class Arena { ...

virtual void* alloc(size t) = 0; virtual void free(void*) = 0;

void operator new(size t sz. Arena* a)

return a.alloc(sz);

Теперь можно отводить память для объектов произвольных типов из различных областей (Arena):

extern Arena* Persistent; постоянная память

extern Arena* Shared; разделяемая память

void g(int i)

X* p = new(Persistent) X(i); X в постоянной памяти



X* q = new(Shared) X(i);

Если мы помещаем объект в область памяти, которая непосредственно не управляется стандартными функциями распределения свободной памяти, то надо позаботиться о правильном уничтожении объекта. Основным средством здесь является явный вызов деструктора:

void h(X* p)

p->~X();

Persistent->free(p);

вызов деструктора освобождение памяти

Заметим, что явных вызовов деструкторов, как и глобальных функций размещения специального назначения, следует, по возможности, избегать. Бывают случаи, когда обойтись без них трудно, но новичок должен трижды подумать, прежде чем использовать явный вызов деструктора, и должен сначала посоветоваться с более опытным коллегой.

6.8 Упражнения

1 . (*1 ) Пусть есть класс

class base {

public:

virtual void iam() { cout << base\n ; }

Определите два производных от base класса и в каждом определите функцию iam(), выдающую имя своего класса. Создайте объекты этих классов и вызовите iam() для них. Присвойте адреса объектов производных классов указателю типа base* и вызовите iam() с помощью этих указателей.

2. (*2) Реализуйте примитивы управления экраном ($$6.4.1) разумным для вашей системы образом.

3. (*2) Определите классы triangle (треугольник) и circle (окружность).

4. (*2) Определите функцию, рисующую отрезок прямой, соединяющий две фигуры. Вначале надо найти самые ближайшие точки фигур, а затем соединить их.

5. (*2) Измените пример с классом shape так, чтобы line было производным классом от rectangle, или наоборот.

6. (*2) Пусть есть класс

class char vec { int sz;

char element [1]; public:

static new char vec(int s);

char& operator[] (int i) { return element[i]; }

Определите функцию new char vec() для отведения непрерывного участка памяти для объектов char vec так, чтобы элементы можно было индексировать как массив element[]. В каком случае эта функция вызовет серьезные трудности?

7. (*1 ) Опишите структуры данных, которые нужны для примера с классом shape из $$6.4, и объясните, как может выполняться виртуальный вызов.

8. (*1 .5) Опишите структуры данных, которые нужны для примера с классом satellite из $$6.5, и объясните, как может выполняться виртуальный вызов.

9. (*2) Опишите структуры данных, которые нужны для примера с классом window из $$6.5.3, и объясните, как может выполняться виртуальный вызов.

X в разделяемой памяти



1 ... 53 54 55 [ 56 ] 57 58 59 ... 120

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика