
8.Перегрузка операций присваивания.
Операция присваивания определена в любом классе по умолчанию как поэлементное копирование. Эта операция вызывается каждый раз, когда одному существующему объекту присваивается значение другого. Если класс содержит поля, память под которые выделяется динамически, необходимо определить собственную операцию присваивания. Чтобы сохранить семантику присваивания, операция-функция должна возвращать ссылку на объект, для которого она вызвана, и принимать в качестве параметра единственный аргумент -- ссылку на присваиваемый объект.
const monstr& operator = (const monstr &M){
// Проверка на самоприсваивание:
if (&M == this) return *this;
if (name) delete [] name;
if (M.name){
name = new char [strlen(M.name) + 1];
strcpy(name, M.name);}
else name = 0;
health = M.health; ammo = M.ammo; skin = M.skin;
return *this;
}
Возврат из функции указателя на объект делает возможной цепочку операций присваивания:
monstr A(10), B, C;
C = B = A;
Операцию присваивания можно определять только как метод класса. Она не наследуется.
9.Дружественные функции и классы.
Иногда желательно иметь непосредственный доступ извне к скрытым полям класса, то есть расширить интерфейс класса. Для этого служат дружественные функции и дружественные классы.
Дружественная функция
Дружественные функции применяются для доступа к скрытым полям класса и представляют собой альтернативу методам. Метод, как правило, описывает свойство объекта, а в виде дружественных функций оформляются действия, не являющиеся свойствами класса, но концептуально входящие в его интерфейс и нуждающиеся в доступе к его скрытым полям, например, переопределенные операции вывода объектов. Ниже перечислены правила описания и особенности дружественных функций.
Дружественная функция объявляется внутри класса, к элементам которого ей нужен доступ, с ключевым словом friend. В качестве параметра ей должен передаваться объект или ссылка на объект класса, поскольку указатель this ей не передается.
Дружественная функция может быть обычной функцией или методом другого ранее определенного класса. На нее не распространяется действие спецификаторов доступа, место размещения ее объявления в классе безразлично.
Одна функция может быть дружественной сразу нескольким классами. В качестве примера ниже приведено описание двух функций, дружественных классу monstr. Функция kill является методом класса hero, а функция steal_ammo не принадлежит ни одному классу. Обеим функциям в качестве параметра передается ссылка на объект класса monstr.
class monstr; // Предварительное объявление класса
class hero{
public:
void kill(monstr &);
...
};
class monstr{
...
friend int steal_ammo(monstr &);
friend void hero::kill(monstr &);
// Класс hero должен быть определен ранее
};
int steal_ammo(monstr &M){return --M.ammo;}
void hero::kill(monstr &M){M.health = 0; M.ammo = 0;}
Использования дружественных функций нужно по возможности избегать, поскольку они нарушают принцип инкапсуляции и, таким образом, затрудняют отладку и модификацию программы.
Дружественный класс
Если все методы какого-либо класса должны иметь доступ к скрытым полям другого, весь класс объявляется дружественным с помощью ключевого слова friend. В приведенном ниже примере классmistress объявляется дружественным классу hero:
class hero{
...
friend class mistress;
}
class mistress{
...
void f1();
void f2();
}
Функции f1 и f2 являются дружественными по отношению к классу hero (хотя и описаны без ключевого слова friend) и имеют доступ ко всем его полям. Объявление friend не является спецификатором доступа и не наследуется.
ПРИМЕЧАНИЕ Обратите внимание на то, что класс сам определяет, какие функции и классы являются дружественными, а какие нет.
10.Константные объекты.
Константный объект - неизменяемый объект. Его данные нельзя изменять, методы можно вызывать только константные. (Два исключения: (1)константный метод может менять mutable-члены, т. е. mutable-данные можно изменить косвенно, путём вызова константного метода; (2) можно изменять статические данные, если они сами не константные). Константный объект инициализируется так: 1) Если объявлен как член класса, то в конструкторе man::man (string n) :name(n) { .... } 2) Если объявлен как статический член класса, то где угодно (в любой единице компиляции*), вне функций/процедур/классов и т. д., с указанием имени класса, без слова static const double math::pi (3.1415926); 3) Если объявлен как глобальные данные, то примерно также const double pi (3.1415926);