Дружественные классы С++

Приступая к изучению темы Дружественные классы, вам необходимо знать, что такое дружественные функции. Тогда вам намного легче будет все понять и мне не придется повторять то, что уже написано в статье о дружественных функциях. Говоря о дружественных классах, хочу отметить, что иногда удобней не объявлять дружественные функции в теле другого класса, а объявить вместо них дружественный класс. Тогда методы этого дружественного класса, автоматически станут дружественными классу, который предоставляет дружбу.

К примеру, если дружественный класс содержит 5 — 10 методов и каждому из них необходим доступ к приватным элементам другого класса. Тогда, объявив дружественный класс, сам код будет выглядеть компактней. Но если доступ к элементам другого класса необходим только нескольким методам дружественного класса, лучше воспользоваться объявлением дружественных функций. Так наши приватные элементы будут более защищены от случайного внесения в них ошибочных данных. И это действительно важно!

Рассмотрим следующий код программы. В нем мы создадим два класса. Один из них объявим дружественным и, используя его методы, внесем изменения в приватные элементы другого класса.

#include <iostream>
#include <string.h>

using namespace std;

class child; //заранее объявляем класс, который станет дружественным 

class schoolchild //определяем следующий класс
{
	char name[16];
	char surname[16];
	int clas;
public:
	schoolchild (char*, char*, int);//конструктор
	void getData();
	friend child;//указываем, что класс дружественный
};	
// определяем методы класса schoolchild
schoolchild::schoolchild(char *n, char *s, int c)
{
	strcpy(name, n);
	strcpy(surname, s);
	clas = c;
}

void schoolchild::getData()
{
	cout << name << " " << surname << "\t" << clas << "-й класс"<< endl;
}

class child //определяем дружественный класс
{
public:
	void changeClas(schoolchild &, int );
	void getChangeData(schoolchild);
};
// определяем методы класса child
void child::changeClas(schoolchild &obj, int newCl) //передаем объект класса и вносим изменения в int clas
{	
	obj.clas = newCl;
}

void child::getChangeData(schoolchild obj)
{
	cout << obj.name << "  " << obj.surname << "\t переведен(а)  в " << obj.clas << "-й класс\n";
}

int main()
{
	setlocale(LC_ALL, "rus");

	//создаем объекты класса schoolchild
	schoolchild visotscaya	( "Маргарита", "Высоцкая", 3);
	schoolchild semenov		( "Александр", "Семенов", 3);

	cout << "Список учеников 3-го класса:\n";
	visotscaya.getData();
	semenov.getData();

	child transfer; //создаем объект transfer - перевод в с следующий класс

	transfer.changeClas(visotscaya, 4);
	transfer.changeClas(semenov, 4);

	cout << "\nПеревод в следующий класс:\n";
	transfer.getChangeData(visotscaya);
	transfer.getChangeData(semenov);

	cout << "\nСписок учеников 4-го класса:\n";
	visotscaya.getData();
	semenov.getData();

return 0;
}

Класс, который будет дружественным,  надо объявить до того, как мы укажем в другом классе, что он является дружественным. Так делается, если само определение дружественного класса описано ниже определения класса, который предоставляет «дружбу». В строке 6  объявляем класс child так как определим его уже ниже в коде, после того как укажем, что он является дружественным классу schoolchild. Далее определяем класс schoolchildстроки 8-17. В поле private этого класса размещены две строки  name[16]surname[16] и переменная clas, которые будут инициализированы  сразу при создании объекта в главной функции main, с помощью конструктора класса, объявленного в  строке 14. В строке 16 указываем, что класс child будет дружественным классу schoolchild  — friend child;.  В определении конструктора класса, используя функцию strcpy, заполняем значениями строки, а так же инициализируем переменную clas — строки 19 — 24. Ниже определяем метод класса, который будет выводить все данные на экран —  void schoolchild::getData().

Строки 31 — 46 — определение класса child и его методов. Как было видно, в классе schoolchild явно не указано, что методы класса child являются дружественными. В нем дружественным  объявлен сам класс child, при этом все его методы автоматически становятся дружественными классу schoolchild. Поэтому, используя методы дружественного класса child, мы можем обращаться к элементам класса schoolchild, даже к приватным, и изменять их значения. Класс child, для простоты восприятия, содержит всего два метода. Определены они в строках 38 — 46.

Метод void changeClas(schoolchild &, int ); принимает в виде параметров адрес объекта класса schoolchild (для того чтобы внести изменения в его приватный элемент) и значение типа int (то значение, которое надо записать в элемент clas). Второй метод, void getChangeData(schoolchild);, просто выводит на экран информацию с измененными данными. Строки 53 — 54  — создаем два объекта класса schoolchild и в скобках задаем значения его элементам. Ниже выводим эти данные на экран. В строке 60 объявляем объект дружественного класса —  child transfer; и через методы класса child обращаемся к объектам и элементам класса  schoolchild. В подтверждение того, что нам удалось сохранить измененные данные в объектах класса schoolchild, мы снова выводим данные на экран используя метод getData();строки 70 — 71

Вот, собственно, результат работы нашей программы:

CppStudio.com

Список учеников 3-го класса:
Маргарита Высоцкая 3-й класс
Александр Семенов 3-й класс

Перевод в следующий класс:
Маргарита Высоцкая переведен(а) в 4-й класс
Александр Семенов переведен(а) в 4-й класс

Список учеников 4-го класса:
Маргарита Высоцкая 4-й класс
Александр Семенов 4-й класс
Для продолжения нажмите любую клавишу . . .

Все, что было задумано, осуществилось — данные приватных элементов изменены и сохранены с помощью методов дружественного класса.

Основная информация, которую необходимо запомнить:

  • чтобы объявить класс дружественным, в теле класса, который предоставляет дружбу, перед именем дружественного класса необходимо использовать зарезервированное слово С++ —  friend;
  • как и в случае с дружественными функциями, нет разницы, в каком поле класса мы объявим дружественный класс —  private, public или protected. Мы все равно сможем обращаться к его методам из главной функции main();
  • если определение дружественного класса располагается ниже определения класса, предоставляющего дружбу, то объявить дружественный класс надо выше. Это поможет избежать ошибок при компиляции;
  • когда класс объявлен дружественным, все его методы так же становятся дружественными, к тому классу в котором он объявлен. При этом методы класса, который разрешил дружбу не имеют доступа к элементам дружественного класса;
  • не следует злоупотреблять и объявлять множество дружественных классов. Помните о том, что мы должны заботься о защите  данных. Иногда целесообразней использовать дружественные функции; 

Пожалуй, этой информации будет достаточно, чтобы продолжить работу и ваши эксперименты с дружественными классами. Если у вас остались вопросы — задавайте их нам. 

Практика

К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!

Автор: Marienko L.
Дата: 29.01.2014
Поделиться:

Комментарии

  1. asduj

    А если не объявлять заранее класс child, то в объявлении класса schoolchild можно написать class

    friend class child

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.