Возникающие проблемы

Классы, использующие свободную память

Преобразования типа

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

Из существующего типа в новый – с помощью одноаргументного конструктора.

Пример для класса Rational:

Rational x = Rational(23); // явный вызов

Rational y = 23; // неявный вызов

Возможны любые использования:

Rational a(1,2), b(1), c;

c = a + b;

c = a + 1; // эквивалентно c = a + Rational(1);

c = 2 + a; // эквивалентно c = Rational(2) + a;

Из нового типа в существующий - с помощью перегрузки оператора преобразования типа

Обязательно функция-член класса.

Прототип: operator имя_типа ();

Реализация: имя_класса::operator имя_типа() { ... }

Использование: неявно при вычислении выражений или явно с помощью обычного оператора преобразования типа: имя_типа(выражение).

Пример для класса Rational:

class Rational{

public:

...

operator float() { return (float) num / den; }

...

};

Использование:

Rational x(3,2);

float f = x;

Еще пример:

while( cin >> n)

cout << n;

Возможные неприятности:

Если в классе Rational есть одноаргументный конструктор (преобразование int в Rational) и в нем будет перегружена операция преобразования типа для int (преобразование Rational в int), тогда конструкция:

Rational a(1,2);

... a + 1 ...

вызовет сообщение об ошибке: два преобразования типа, определенные пользователем; что выбрать: int + int или Rational + Rational?

Причины, по которым приходится создавать классы с динамическим управлением памятью. Пример такого класса: функция, заданная таблично. Состояние класса включает в себя информацию о размере таблицы (количество узлов в задании функции) и массивы для хранения значений аргумента (х) и соответствующих значений функции (y). Массивы определяются через соответствующие указатели, размер таблицы определяет требуемый объем памяти. Кто выделит память? - конструктор. Пример разработки соответствующего класса.

class Function{

private:

float * Ptrx, * yPtr;

int size;

public:

Function(); // пустой конструктор

Function(int sz); // инициализирующий конструктор

~Function();

. . .

};

Function::Function()

{

size = 0;

xPtr = yPtr = NULL;

}

Function::Function(int sz)

{

size = sz;

xPtr = new float[size];

yPtr = new float[size];

}

Function::~Function()

{

delete [] xPtr;

delete [] yPtr;

}

Если в прикладной программе в некотором внутреннем блоке создается переменная типа “Указатель на класс” и ей присваивается значение некоторой другой – глобальной переменной: для классов (структур) определена операция присваивания - побайтное копирование:

Function f1[5]; f1 5 f2 5

. . .

{

Function f2;

f2 = f1;

. . .

}

 

В момент выхода из блока переменная f2 разрушается – для нее работает деструктор класса. В результате будет разрушена и переменная f1!

Результат не изменится, если во внутреннем блоке вместо присваивания использовать инициализацию (в этом случае будет работать копирующий конструктор по умолчанию – тоже побайтное копирование):

{

Function f2 = f1;

. . .

}