| HTML [44] |
| Visual C++ и MFC [21] |
| c++ [78] |
| php [19] |
| Javascript [15] |
| C# [51] |
| загрузки [0] |
|
XNA [10]
создание игр с помощью xna
|
| Главная » Статьи » c++ |
Итак, мы уже познакомились с одним из основных правил ООП: поля-данные (переменные) класса должны быть защищены от внешнего воздействия, то есть доступ к ним можно получить только с помощью функций-членов данного класса. Тем не менее, как показывает практика, иногда необходимо получить прямой доступ к полям-данных класса, не используя его интерфейс. Т.е. чуть-чуть отступить от правил и обратиться к полям-данных класса через функцию или функцию-член другого класса. Зачем это может понадобиться? Одна из причин может быть следующей, например - при доступе к внутренним переменным класса через его функции уменьшается эффективность работы за счет затрат на вызов функции. В большинстве случаев это не критично, но не всегда. В некоторых случаях это может играть существенную роль. Конечно, можно добавить новый метод к классу для получения прямого доступа к внутренним переменным. Однако, в большинстве случаев, интерфейс класса спланирован для выполнения определенного круга операций, и наша функция может оказаться как бы ни у дел. Или, еще один пример, нам необходимо получить прямой доступ к внутренним данным двух разных классов. Вот здесь-то и возникает проблемка... Для решения подобного круга задач в С++ и существует возможность описания функции, функции-члена другого класса как дружественной (friend). Класс может предоставлять особые привилегии определенным внешним функциям или функциям-членам другого класса. Вот эти функции и получили название дружественных. Рассмотрим как работает этот механизм. Для описания функции (функции-члена) дружественной тому или иному классу, необходимо в описании этого класса объявить дружественную функцию, используя ключевое слово friend. Причем, обратите внимание, не играет никакой роли в каком из разделов класса Вы разместите объявление дружественной функции. Согласитесь, небольшие нарушения ограничения доступа могут быть весьма полезны, если их использовать с достаточной осторожностью. Словосочетание "с достаточной осторожностью" обозначает, что функция или класс, пользующиеся привилегиями доступа должны быть очень тесно связаны с тем классом, который наделил их этими привилегиями. Главной целью использования дружественных функций и классов является повышение эффективности программы. Дружественные функции и классы могут осуществлять прямой доступ к закрытым полям объекта без использования функций-членов этого класса. Рассмотрим пример использования дружественной функции (объяснение приводится в коментариях): #include <iostream.h>
class A //интерфейс (протокол) класса A
{
//закрытая область данных
private: //хотя, по умолчанию, действует модификатор
//доступа private
//для читабельности программы мы его укажем явно
int pole; //вот эта переменная и будет нашей подопытной
//открытая область данных
public:
A(){ //конструктор по умолчанию
pole=55;//инициализация закрытой переменной
//выведем на экран сообщение, что
//конструктор отработал
cout<<"Constructor A\n";
}
//объявление дружественной функции которая принимает экземпляр класса A
friend void ourfriend(const A &f);
};
//раз объявили дружественную функцию, то давайте уже и реализуем ее
void ourfriend(const A &f)
{
//итак, для демонстрации работы дружественной функции, мы обратимся
//к закрытой переменной pole экземпляра класса f и выведем ее
//значение на экран.
cout<<"\nWow! We have free access to private members,\n";
cout<<"pole ="<<f.pole<<endl;
}
void main()
{
A example; //создали экземпляр класса А - example
ourfriend(example); //собственно тестирование дружественной
//функции
}
Результат выполнения программы: Constructor A Wow! We have free access to private members, pole =55 Итак, мы смогли получить доступ к закрытой переменной класса из функции (которая, при этом, не является членом класса), используя механизм дружественных функций. Заметим, что при работе с дружественной функцией следует помнить о том, что она не имеет указателя this класса в котором она объявлена как дружественная. Почему?.. Ответ мы найдем в самом смысле использования дружественных функций: дружественная функция не является членом этого класса. Если все функции-члены одного класса являются дружественными функциями другого класса, то это можно записать как: friend class имя_класса; Может ли функция быть дружественной нескольким классам? Да, но если функция дружественна нескольким классам, то надо добавить это описание во все классы, к внутренним данным которых будет производиться обращение. Подозреваем, что у Вас возник вопрос: "А как же быть с защищенностью данных, если можно получить доступ к данным напрямую?" Не волнуйтесь, с точки зрения использования механизма инкапсуляции (напомним, под этим понятием мы подразумеваем сокрытие данных) защищенность данных сохраняется, поскольку полностью исключается всякая возможность доступа к данным так, чтобы объект не был осведомлен об этом. То есть в дружественных функциях мы свободно работаем только с экземплярами даного класса, но не с самим классом. Снова, рассмотрим пример, но на этот раз, в роли дружественных функций у нас будут выступать функции-члены. #include <iostream.h>
class A //интерфейс (протокол) класса A
{
//открытая область данных
public:
A(){ //конструктор по умолчанию
cout<<"Constructor A\n";
//конструктор отработал
}
//функция-член FriendToB() будет использоваться как
//дружественная функция для класса B
void FriendToB();
void SomeFunction();
};
class B //интерфейс (протокол) класса B
{
//область закрытых данных
private:
int i,j; //наши "подопытные" закрытые переменные;
//если сможем обратиться к этим переменным
//из дружественной функии FriendToB(), то
//"опыт удался"
//область открытых данных
public:
B(){
i=10; //произведем инициализацию
j=17;
cout<<"Constructor B\n";
//конструктор отработал
}
//укажем, что класс B имеет дружественную функцию, которая
//является функцией-членом класса A
friend void A::FriendToB();
};
class C //интерфейс (протокол) класса C
{
//область закрытых данных
private:
int k,n; //закрытые
//область открытых данных
public:
C(){
k=4; //начальная инициализация
n=7;
cout<<"\n\nConstructor C\n";
//конструктор отработал
}
//укажем что ВСЕ функции-члены класса A, являются
//дружественными для даного класса
friend class A;
};
//действительно ли может функция-член одного
//класса обращаться к закрытым данным другого
//класса. Давайте проверим!
void A::FriendToB()
{
B example; //объявим экземпляр класса B
cout<<"So, variables' value are:\n";
//и произведем доступ к закрытым данным
cout<<"example.i="<<example.i;
cout<<"\nexample.j="<<example.j<<endl;
}
//действительно ли после объявления в классе С
//friend class A; -все функции-члены класса A
//станут дружественными функциями для класса С?
//Ведь мы нигде не указывали, что функция-член
//SomeFunction() является дружественной классу С.
//Надо проверить...
void A::SomeFunction()
{
C temp; //объявим экземпляр класса С
cout<<"And now we are testing friend class...\n";
//и произведем доступ к закрытым данным
cout<<"temp.k="<<temp.k;
cout<<"\ntemp.n="<<temp.n<<endl;
}
void main()
{
A test; //создали экземпляр класса А - example
//собственно тестирование дружественной функции классу B
test.FriendToB();
//проверим, все ли функции-члены класса A являются дружественными
//классу С (на примере, функции SomeFunction)
test.SomeFunction();
}
Вот что будет выведено на экран, в результате выполнения программы: Constructor A Constructor B So, variables' value are: example.i=10 example.j=17 Constructor C And now we are testing friend class... temp.k=4 temp.n=7 Итак, если функция или функция-член объявлены как дружественные, то такие функции или функции-члены такого класса могут осуществлять непосредственный доступ ко всем (private, protected, public) данным (полям-данным и функциям-членам) класса, для которого они дружественны. | |
| Просмотров: 11922 | Рейтинг: 4.2/5 |
| Всего комментариев: 0 | |