Программирование >>  Синтаксис инициирования исключений 

1 ... 54 55 56 [ 57 ] 58 59 60 ... 82


2. Реализуется схема сборки мусора, которая позволяет найти все указатели и указываемые объекты. Мы помечаем все указываемые объекты, на которые ссылается хотя бы один указатель, а затем удаляем все непомеченные указываемые объекты.

Подсчет ссылок используется не так часто, но наша задача прямо-таки создана для него. Сборка мусора - тема, над которой нам предстоит основательно поразмыслить в главе 1 6.

Ведущие указатели

Невидимые указаьели чаще всего являются ведущими (то есть между указателем и указываемым объектом существует однозначное соответствие). С момента рассмотрения ведущих указателей прошло немало времени, поэтому я кратко напомню, что нам предстоит сделать для поддержания семантики ведущих указателей в нашей ситуации:

1 . Когда указатель уничтожается, должен уничтожаться и указываемый объект.

2. Когда указатель копируется, должен копироваться и указываемый объект.

3. Когда для указателя выполняется присваивание, он изменяется так, чтобы ссылаться на копию указываемого объекта из правой части выражения.

Недостаточно присвоить указываемый объект из правой части указываемому объекту из левой части, поскольку они могут принадлежать к разным классам.

Уничтожение

Деструктор класса-предка должен быть виртуальным, а деструктор указателя должен уничтожать указываемый объект.

class Foo { public:

virtual ~Foo() {}

В файле foo.cpp

class PFoo : public Foo {

private:

Foo* foo; public:

virtual ~PFoo() { delete foo; }

Копирование

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

class Foo { protected:

Foo(const Foo&) {} public:

virtual Foo* makeClone() = 0; Для копирования

В файле foo.cpp

class PFoo : public Foo {

private:

Foo* foo; public:

PFoo(Foo* f) : foo(f) {}



virtual Foo* makeClone() { return new PFoo(foo->makeClone()); }

class Bar : public Foo { protected:

Bar(Bar&); Конструктор копий public:

virtual Foo* makeClone();

Foo* Bar::makeClone()

return new Bar(*this);

Наконец мы добрались и до применения настоящего конструктора копий. Указатель создает копию - не только свою, но и указываемого объекта. В свою очередь, указываемый объект перекладывает всю тяжелую работу на свой собственный конструктор копий. Обратите внимание: чтобы это стало возможным, мы сделали конструктор копий Foo защищенным.

Присваивание

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

class Foo { public:

virtual Foo& operator=(const Foo&);

В файле foo.cpp

class PFoo : public Foo {

private:

Foo* foo; public:

virtual Foo& operator=(const Foo& f)

if (this == &f) return *this; delete foo;

foo = f.foo->makeClone(); return *this;

Foo& Foo::operator=(const Foo&)

return *this;

Снова о двойной передаче

Невидимые указатели позволяют элегантно решить многие проблемы. Одна из таких проблем - улучшенная инкапсуляция двойной передачи, и в том числе решение неприятной проблемы, связанной с оператором +=. Мы объединим двойную передачу с концепцией переходных типов, о которых говорилось давным-давно, в главе 7.



Удвоенная двойная передача

Итак, давайте попробуем реализовать двойную передачу для невидимых указателей. Этот раздел представляет собой элементарное распространение приемов, которыми мы пользовались без связи с указателями.

Первая попытка

Сейчас мы сделаем первый заход на арифметические операции с невидимыми указателями. Он работает, но обладает некоторыми ограничениями, на которые следует обратить внимание и должным образом исправить. Чтобы избежать проблем, связанных с возвращением ссылок на временные значения (см. окончание главы 11), я перехожу на использование оператора new. Проблемы сборки мусора будут рассматриваться позже.

В файле number.h

class NBase; Клиентам об этом ничего знать не нужно

class Number {

protected:

Number(const Number&) {}

Number() {}

public:

virtual NBase& operator+(const NBase&) = 0; virtual Number& operator+(const Number&) = 0; И т.д.

В файле number.cpp class Integer; class Real;

class PNumber : public Number { private:

NBase* number; protected:

virtual NBase& operator+(const NBase& n) const { return *number + n; } #2

public:

PNumber(NBase* n) : number(n) {}

virtual Number& operator+(const Number& n) const

{ return *(new PNumber(&(n + *number))); } #1

class NBase : public Number {

Промежуточный базовый класс

Традиционная двойная передача в NBase

public:

virtual NBase& operator+(const Integer&) const = 0; virtual NBase& operator+(const Rea1&) const = 0; И т.д.

virtual NBase& operator+(const NBase&) const = 0; virtual Number& operator+(const Number& n) const

{ return Integer(0); } Заглушка не вызывается

class Integer : public NBase {



1 ... 54 55 56 [ 57 ] 58 59 60 ... 82

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