Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP.doc
Скачиваний:
13
Добавлен:
25.04.2019
Размер:
1 Мб
Скачать
☆

Return *this;

}

CString & CString::operator = (const char * szSourceString) {

...

Return *this;

}

В результате такой перегрузки появляется возможность присваивать объектам класса CString другие объекты этого же класса или строки const char *.

Если для спецификации возвращаемого значения в operator = использовать что-либо отличное от ссылки на класс (например, void, CString, const CString &), то станут невозможными последовательные цепочки присваиваний, которые допускаются для встроенных типов. Если в функции operator = осуществлять возврат чего-либо, отличного от *this (например, ссылку на аргумент функции), то будет невозможна либо компиляция функции operator =, либо компиляция пользовательского кода.

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

template <class T> class NamedPtr { // поименованные указатели

public:

...

NamedPtr & operator = (const NamedPtr & srcPtr);

~NamedPtr() { delete __actualptr; }

private:

T * __actualptr; // фактический указатель

string __name; // имя указателя

};

template <class T>

NamedPtr<T> & NamedPtr<T>::operator = (const NamedPtr & srcptr)

{

...

__name = srcptr.__name; // копируем имя

__actualptr = new T; // выделяем память под значение

*__actualptr = *srcptr.__actualptr; // копируем значение

// предполагается, что операция T::operator= определена

return *this;

}

Очередная проблема при работе с operator = – это необходимость отслеживания присваиваний между одним и тем же объектом, т.е. когда некоторый объект указан и в левой, и в правой части присваивания. Ее опасность состоит в возможности утечек памяти и, что самое главное, обращения к удаленным динамическим компонентам. Для иллюстрации далее приводится неправильное определение функции operator = для некоторого класса SomeClass:

class SomeClass {

public:

...

SomeClass & operator = (const SomeClass & src);

private:

char * Name;

...

};

SomeClass & SomeClass::operator = (const SomeClass & src) {

delete[] Name; // очищаем память

// выделяем новый «кусок» памяти

Name = new char [strlen(src.Name) + 1];

// Но здесь Name уже не определен!

strcpy(Name,src.Name);

return *this;

}

Поскольку оператор delete[] освобождает память, на которую указывают и this–>Name и src.Name, результат функции strlen(src.Name) не определен. Это и является источником проблемы.

Наконец, последняя проблема в работе с функцией operator = связана с ее использованием в классовых иерархиях. Когда некоторый класс B наследует от класса A, то функция B::operator = должна работать с учетом того, что всякий объект класса B является также и объектом класса A. Соответственно эта функция должна присваивать не только те компоненты, которые были введены в классе B, но и компоненты, унаследованные от класса A; в противном случае данные класса A в объекте останутся неизмененными33. Для решения этой проблемы функция operator = может явно вызывать аналогичную функцию базового класса, чтобы присвоить данные объекта базового класса. Однако такой подход работает не всегда. Ниже представлен другой вариант реализации функции operator = (функция является членом класса D, производного от класса B):

D & D::operator = (const D & srcobj) {

if (this == &srcobj) return *this; // самому себе не присваивать!

/* неявно вызываем B::operator= для присваивания данных класса B */

static_cast<B&>(*this) = srcobj;