Статические методы предназначены для обращения к статическим полям класса. Они могут обращаться непосредственно только к статическим полям и вызывать только другие статические методы класса, потому что им не передается скрытый указатель this. Обращение к статическим методам производится так же, как к статическим полям -- либо через имя класса, либо, если хотя бы один объект класса уже создан, через имя объекта.
class A{
static int count; // Поле count -- скрытое
public:
static void inc_count(){ count++; }
...
};
...
A::int count; // Определение в глобальной области
void f(){
A a;
// a.count++ -- нельзя, поле count скрытое
// Изменение поля с помощью статического метода:
a.inc_count(); // или A::inc_count();
}
Статические методы не могут быть константными (const) и виртуальными (virtual).
Иногда желательно иметь непосредственный доступ извне к скрытым полям класса, то есть расширить интерфейс класса. Для этого служат дружественные функции и дружественные классы.
Дружественные функции применяются для доступа к скрытым полям класса и представляют собой альтернативу методам. Метод, как правило, описывает свойство объекта, а в виде дружественных функций оформляются действия, не являющиеся свойствами класса, но концептуально входящие в его интерфейс и нуждающиеся в доступе к его скрытым полям, например, переопределенные операции вывода объектов.
Ниже перечислены правила описания и особенности дружественных функций.
Дружественная функция объявляется внутри класса, к элементам которого ей нужен доступ, с ключевым словом 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 не является спецификатором доступа и не наследуется.
![]()
ПРИМЕЧАНИЕ Обратите внимание на то, что класс сам определяет, какие функции и классы являются дружественными, а какие нет.
![]()
Деструктор -- это особый вид метода, применяющийся для освобождения памяти, занимаемой объектом. Деструктор вызывается автоматически, когда объект выходит из области видимости:
для локальных объектов -- при выходе из блока, в котором они объявлены;
для глобальных -- как часть процедуры выхода из main;
для объектов, заданных через указатели, деструктор вызывается неявно при использовании операции delete.
![]()
ВНИМАНИЕ Автоматический вызов деструктора объекта при выходе из области действия указателя на него не производится.
![]()
Имя деструктора начинается с тильды (~), непосредственно за которой следует имя класса. Деструктор:
не имеет аргументов и возвращаемого значения;
не может быть объявлен как const или static;
не наследуется;
может быть виртуальным (см. раздел "Виртуальные методы").
Если деструктор явным образом не определен, компилятор автоматически создает пустой деструктор.
Описывать в классе деструктор явным образом требуется в случае, когда объект содержит указатели на память, выделяемую динамически -- иначе при уничтожении объекта память, на которую ссылались его поля-указатели, не будет помечена как свободная. Указатель на деструктор определить нельзя.
Деструктор для рассматриваемого примера должен выглядеть так:
monstr::~monstr() {delete [] name;}
Деструктор можно вызвать явным образом путем указания полностью уточненного имени, например:
monstr *m; ...
m -> ~monstr();
Это может понадобиться для объектов, которым с помощью перегруженной операции new выделялся конкретный адрес памяти. Без необходимости явно вызывать деструктор объекта не рекомендуется.