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) данным (полям-данным и функциям-членам) класса, для которого они дружественны. | |
Просмотров: 11880 | Рейтинг: 4.2/5 |
Всего комментариев: 0 | |