Примеры использования дружественных функций и дружественных классов в языке программирования C++

NovaInfo 29, скачать PDF
Опубликовано
Раздел: Технические науки
Просмотров за месяц: 8
CC BY-NC

Аннотация

В статье рассматривается несколько примеров, демонстрирующих основные принципы дружественности, принятые в языке программирования C++. Приведенные реализации могут рассматриваться при изучении объектно-ориентированного программирования и будут интересны как школьникам, так и студентам.

Ключевые слова

ПРОГРАММИРОВАНИЕ, ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ, C++, ДРУЖЕСТВЕННЫЕ ФУНКЦИИ, ДРУЖЕСТВЕННЫЕ КЛАССЫ

Текст научной работы

Язык программирования C++ широко используется для разработки программного обеспечения, и является одним из самых популярных языков программирования. Область его применения включает создание операционных систем, разработку прикладных программ, написание драйверов устройств, а также развлекательных приложений. В настоящее время существует множество реализаций языка C++, как коммерческих, так и бесплатных (например, Microsoft Visual C++ 2005-2013).

Особое внимание при изучении программирования следует уделять объектно-ориентированному программированию [1], при этом первоначальное ознакомление с ним можно проводить, в том числе, и на основе языка Pascal [3]. Однако, по мнению автора, более предпочтительно все-таки использование языка программирования C++, в котором объектовый тип чаще называют классом. Классы позволяют моделировать объекты, имеющие атрибуты (данные-элементы, представляемые в виде полей) и варианты поведения или операции (функции-элементы, функции-члены или методы класса).

В данной статье автор предлагает несколько примеров, посвященных изучению отношения дружественности в языке программирования C++ [5]. Предполагается, что учащиеся уже имеют базовые представления о языке программирования C++ и о разработке классов на его основе.

Известно, что функции, объявленные как дружественные некоторому классу, имеют доступ к закрытым элементам privateprotected) данного класса и используются для повышения производительности; они определяются вне области действия класса. Так, например, дружественную функцию целесообразно использовать в случае организации взаимодействия нескольких объектов разных классов, когда обеспечивающая такое взаимодействие функция должна иметь доступ к закрытым полям нескольких объектов. При этом функция или класс в целом могут быть объявлены другом другого класса. Объявление дружественности не зависит от спецификаторов доступа, и обычно дружественные функции объявляются в начале тела класса.

Для объявления функции другом класса перед ее прототипом в описании класса указывают ключевое слово friend. Например, чтобы объявить класс Class_2 другом класса Class_1, нужно в определении класса Class_1 записать объявление в форме: friend Class_2.

Приведем пример использования дружественной функции двух классов – класса «Правильный треугольник» и класса «Окружность», которая проверяет, можно ли поместить заданную окружность внутри заданного треугольника.

#include "stdafx.h"
#include 
#include 
using namespace std;
class Triangle;
class Circle
  {friend bool Relation(Triangle,Circle);
   public:
     Circle(float x=1) {r=x;}
     void Set(float x) {r=x;}     //Задание радиуса окружности
   private:
     double r;                          //Радиус окружности
   };
class Triangle
  {friend bool Relation(Triangle,Circle);
   public:
     Triangle(double x=1) {a=x;}
     void Set(double x) {a=x;}    //Задание стороны треугольника
   private:
     double a;                            //Сторона треугольника
   };
bool Relation(Triangle A, Circle B)
  {if (B.r

Дружественная некоторому классу функция может являться компонентной функцией другого класса. Для демонстрации этого рассмотрим предыдущий пример, в котором функция Relation() является одним из методов класса Triangle, и при этом объявлена дружественной классу Circle.

#include "stdafx.h"
#include 
#include 
using namespace std;
class Circle;
class Triangle
  {public:
     Triangle(double x=1) {a=x;}
     bool Relation(Circle);
     void Set(double x) {a=x;}     //Задание стороны треугольника
   private:
     double a;                             //Сторона треугольника
   };
class Circle
  {friend bool Triangle::Relation(Circle); //Дружественная функция-
                                                                //метод класса Triangle
   public:
     Circle(double x=1) {r=x;}
     void Set(double x) {r=x;}     //Задание радиуса окружности
   private:
     double r;                             //Радиус окружности
   };
bool Triangle::Relation(Circle A)
  {if (A.r

Как было отмечено выше, кроме дружественной функции для данного класса можно объявить дружественным целый класс. При этом все методы дружественного класса имеют доступ к закрытым и защищенным компонентам того класса, в котором он объявлен другом. Рассмотрим взаимодействие дружественных классов на основе следующего примера, в котором кроме класса «Клиент банка» определен еще и класс «Банк». Взаимодействие этих классов организовано таким образом, что класс Bank объявлен дружественным классу Client (методы класса Bank будут иметь доступ к закрытым полям и методам класса Client). Класс «Банк» хранит список всех своих клиентов, причем этот список оформлен в виде динамического односвязного списка (это позволяет не накладывать ограничений на максимально допустимое количество клиентов банка). При этом класс «Клиент банка» организован таким образом, что в нем все поля и методы, в том числе и конструктор с деструктором, описаны в разделе private. Это означает, что в основной программе будет запрещено даже создание экземпляра объекта класса Client.

#include "stdafx.h"
#include 
#include 
#include 
using namespace std;
class Bank;
class Client
 {friend class Bank;        //Объявление дружественного класса
   private:
     Client(char*, char*, double);
     char* Name;           //ФИО клиента
     Client *NEXT;        //Адрес следующего клиента в списке клиентов
     char Nomer[1][5]; //Номер счета клиента
     double Sum;            //Сумма на счету клиента
     void Out();              //Вывод информации о клиенте
     void Set();               //Ввод информации о клиенте
      ~Client() {delete [ ]Name;}  };
  Client::Client(char* Ch="No Name", char* N="00000", double S=0)
              {Name=new char[strlen(Ch)+1];
               strcpy(Name,Ch);
               strcpy(Nomer[0],N);
               Sum=S;}
  void Client::Out()
           {cout>Nomer[0];
            cout>Sum;}
class Bank
 {public:
    Bank(char*);
    double Percent;                //Процентная ставка по вкладу
    void AddPercent(char*);  //Начисление процентов на счет клиента
    void ChangeSum(char*, double); //Добавление (снятие) суммы со
     //счета
    void OutAllClient();  //Вывод информации о всех клиентах
    void AddClient();     //Добавление нового клиента в список клиентов
   ~Bank();                   //Деструктор
  private:
     int Count;                  //Количество клиентов банка
     char BankName[30]; //Название банка
     Client* BEGIN;        //Адрес первого клиента в списке клиентов
     Client* END;            //Адрес последнего клиента в списке клиентов
 };
  Bank::Bank(char* Ch)
            {Count=0;
             BEGIN=END=NULL;
             strcpy(BankName,Ch);
             Percent=0.1;}
  void Bank::AddPercent(char* Ch)
         {Client* Vrem;
          int i,j;
          Vrem=BEGIN;
          while (Vrem) {j=0;
                                 for (i=0; iNEXT;} }
  void Bank::ChangeSum(char* Ch, double p)
         {Client* Vrem;
          int i,j;
          Vrem=BEGIN;
          while (Vrem) {j=0;
                                  for (i=0; i=0) (*Vrem).Sum+=p;
                                       else coutNEXT;} }
  void Bank::AddClient()
         {if (Count) {END->NEXT=new Client;
                             END=END->NEXT;
                             END->Set();
                             END->NEXT=NULL;}
          else {BEGIN=new Client;
                   END=BEGIN;
                   END->NEXT=NULL;
                   END->Set();}
          Count++;}
  void Bank::OutAllClient()
         {Client* Vrem;
          Vrem=BEGIN;
          coutOut();
                                  Vrem=Vrem->NEXT;} }
  Bank::~Bank()
             {if (Count) {Client* Vrem=BEGIN;
                                 while (Vrem) {Vrem=BEGIN->NEXT;
                                                         delete BEGIN;
                                                         BEGIN=Vrem;} } }
int main()
{ setlocale(LC_ALL,"Rus"); 
  Bank A("УралСиб");
  char c=0;
  while (c!=27)
     { cin.sync();
       A.AddClient();
       cout

Дружественность не обладает ни свойством симметричности, ни свойством транзитивности. Это означает, что если класс А – друг класса В, а класс В – друг класса С, то отсюда не следует, что: класс А – друг класса С; класс В – друг класса А, класс С – друг класса В.

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

В заключение отмечу, что в плане проверки уровня усвоения учащимися учебного материала может оказаться удобным использование всевозможных программ-тестов [6, 7] .

Хочется также отметить следующее: чтобы научиться программировать, далеко не достаточно прочитать книгу, посвященную тому или иному языку программирования, надо писать свои программы, постепенно усложняя поставленные перед собой задачи [4, 8]. Прежде чем писать программу для решения конкретной задачи, необходимо досконально понять задачу и тщательно спланировать пути ее решения. Конечно, тщательное планирование следует относить в какой-то мере только к небольшим задачам, так как в процессе реализации большого проекта, возможно, придется отказаться от намеченного алгоритма решения задачи (или какой-то ее части) в пользу какого-либо более оптимального алгоритма. Кроме того, необходимо постоянно находиться в творческом поиске, так как путей решения поставленной задачи может быть несколько [2].

Читайте также

Список литературы

  1. Бабушкина И.А., Окулов С.М. Практикум по объектно-ориентированному программированию. – М.: "БИНОМ. Лаборатория знаний". 2012. – 371 с.
  2. Дмитриев В.Л., Ахмадеева Р.З. Развитие конструктивного мышления при изучении программирования // Информатика и образование. 2009. № 2. – С. 69-73.
  3. Дмитриев В.Л. Развитие представлений об объектном программировании на примере разработки объектов в среде программирования Turbo Pascal // Информатика в школе. 2014. № 2 (95). – С. 54-59.
  4. Дмитриев В.Л. Теория и практика решения задач по программированию. Ч.1. Уфа: РИЦ БашГУ. 2007. – 264 с.
  5. Дмитриев В.Л. Теория и практика программирования на С++. – Стерлитамак: РИО СФ БашГУ. 2013. – 315 с.
  6. Дмитриев В.Л. Тестирование в игровой форме как способ проверки усвоения учебного материала // Информатика в школе. 2012. №10 (83). – С. 41-43.
  7. Дмитриев В.Л. Компьютерная программа для проведения тестирования с поддержкой произвольного расположения материалов теста // Информатика и образование. 2014. №2 (251). – С. 74-77.
  8. Окулов С.М. Программирование в алгоритмах. – М.: БИНОМ. Лаборатория знаний. 2002. – 341 с.

Цитировать

Дмитриев, В.Л. Примеры использования дружественных функций и дружественных классов в языке программирования C++ / В.Л. Дмитриев. — Текст : электронный // NovaInfo, 2014. — № 29. — URL: https://novainfo.ru/article/2849 (дата обращения: 29.09.2022).

Поделиться