Самым важным, но и, скорее всего, самым непонятным для вас сейчас станет определение дружественной функции. Дружественная функция — это функция, которая не является членом класса, но имеет доступ к членам класса, объявленным в полях private или protected. Долго не вникайте в суть этого определения, а лучше сразу переходите к следующему абзацу. Обещаю, что после прочтения статьи вы вернетесь к этому определению и вас посетит мысль: «Ну да — так и есть! Тут все понятно!»
Приступим к основному занятию программиста — практике! В примере запрограммируем следующее: создадим класс Woman25, который, используя дружественные функции и обычные методы класса, будет получать данные об объекте (имя и вес) и выводить их на экран. Методы и friend-функции будут выполнять аналогичные действия. В этом и есть особенная польза данного примера — вы сможете посмотреть отличия в объявлении и определении дружественных функций от обычных методов класса. На основании полученных данных, программа даст пользователю совет относительно корректировки его веса. Ну что-же, лучше один раз увидеть…
#include <iostream>
#include <string.h>
using namespace std;
class Woman25
{
private:
char *name;//имя
int weight;//вес
friend void setData(char *, int, Woman25&);//объявление дружественных функций
friend void getData(Woman25&);
public:
Woman25()//конструктор
{
name = new char [20];
strcpy(name, "Норма");
weight = 60;
}
~Woman25()//деструктор
{
delete [] name;
cout << "!!! Деструктор !!!" << endl;
}
void setData(char*, int);//объявление методов класса
void getData();
void advise();
};
void setData(char *n, int w, Woman25& object)//определяем friend-функцию setData
{
strcpy(object.name, n);////////////
object.weight = w;
}
void getData(Woman25& object)//определяем friend-функцию getData
{
cout << object.name << "\t: " << object.weight << " кг" << endl;
}
void Woman25::setData(char *n, int w)//определяем set-метод класса
{
strcpy(name, n);
weight = w;
}
void Woman25::getData()//определяем get-метод класса
{
cout << name << "\t: " << weight << " кг" << endl;
}
void Woman25::advise()//определяем метод класса Совет (advise)
{
if(weight < 55){ //если вес меньше 55 кг
cout << "Вам надо потреблять больше калорий!" << endl;
cout << "=====================================" << endl << endl;
}else if(weight >= 55 && weight <= 65){ //если вес в пределах 55-65 кг
cout << "Ваш вес в норме!" << endl;
cout << "=====================================" << endl << endl;
}else { //если вес > 65 кг
cout << "Вам надо ограничивать себя в еде!" << endl;
cout << "=====================================" << endl << endl;
}
}
int main()
{
setlocale(LC_ALL, "rus");
Woman25 Norm; //создаем объект Norm, сработает конструктор и weight будет = 60, name - Норма
Norm.getData(); //вызов метода класса
cout << "=====================================" << endl << endl;
Woman25 Anna; //второй объект
Anna.setData("Анна", 100);
Anna.getData();
Anna.advise();
Woman25 Inna; //третий объект
setData("Инна", 50, Inna);
getData(Inna);
Inna.advise();
return 0;
}
Комментарии к исходному коду.
В строках 6 — 30 создаем класс Woman25. Он содержит два приватных элемента класса: char *name; и int weight;. В private также объявим дружественные функции friend void setData(char *, int, Woman25&); и friend void getData(Woman25&);. Хотя их можно объявлять и определять в любом поле класса, будь то private, public или protected, но об этом поговорим позже. Так мы сделали, чтобы показать, что несмотря на объявление дружественных функций в поле private, к ним можно обращаться напрямую из функции main(). Тогда, когда методы класса должны располагаться в поле public всегда, если мы собираемся вызывать их вне класса. Объявление дружественных функций отличается от объявления методов класса еще и тем, что перед типом возвращаемого функцией значения используется зарезервированное слово friend. Обратите внимание, что в виде параметра мы передаем этим функциям ссылку на объект нашего класса - Woman25&. В обычных методах этого не будет. В поле public расположился конструктор класса — строки 15 — 20. В нем мы задаем значение нормального веса - 60 кг, а так же, с помощью функции strcpy(name, "Норма");, вносим данные в элемент класса name. Затем в строках 21 — 25 определяем деструктор класса ~Woman25(). Его задача, освободить, выделенную конструктором, динамическую память. А для того, чтобы убедиться, что он сработал и удалил динамическую память всех созданных объектов класса при завершении работы программы, мы добавили в него строку cout << "!!! Деструктор !!!" << endl; . Строки 27 — 29 - объявление обычных методов класса.
Теперь начинается, пожалуй, самое интересное — определение вне класса наших дружественных функций и обычных методов класса. Все это располагается в строках 32 - 66. Смотрите, когда мы определяем дружественные функции , строки 32 — 36 и 38 — 41, мы не используем оператор :: двойное двоеточие (область видимости метода). Это уже говорит нам о том, что дружественная функция не принадлежит классу, не является его компонентом. А при определении остальных методов использование оператора :: является обязательным. Метод класса advise(), на основании полученных данных о весе, дает пользователю один из советов либо сообщает, что вес в норме.
Переходим в главную функцию — строки 68 — 87. Тут мы создаем объект класса Woman25 Norm;, при создании которого сработает конструктор и инициализирует элементы name и weight. Вызываем метод класса Norm.getData(); чтобы вывести на экран значение нормы. Со вторым созданным объектом Woman25 Anna; работаем, вызывая обычные set и get- методы класса, а с третьим объектом Woman25 Inna; — вызывая дружественные функции. Как видите, вызываются они как функции, которые не принадлежат классу. Объект класса мы передаем, как параметр.