Для того, чтобы предоставить легкий доступ к данным класса механизм с помощью ключа public не всегда удобен, ведь в этом случае public-переменные становятся общедоступны, то есть к ним может обратиться кто угодно из любой части программы. Механизм под названием «друзья класса» действует более гибко и позволяет предоставлять доступ избирательно. Например, можно предоставить доступ к закрытым переменным класса только для какой-либо функции или класса.
Друзья класса – это функции и классы, у которых есть полный доступ к классу, такой же, как у методов класса. Для получения прав друга, функция должна быть описана в классе со спецификацией friend.
Например, определим независимую функцию, которая вводит данные с клавиатуры в объект класса MyStr. Для этого в классе MyStr необходимо описать прототип дружественной функции:
Дружественная функция имеет два параметра , первый – ссылка на объект класса MyStr в который будет производиться ввод, второй - ограничитель ввода (максимальное число символов в строке). Описание дружественной функции размещаем в глобальной области программы.
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
using namespace std;
class MyStr
{ static int count; // счетчик существующих строк
char *buf; // закрытые данные
// прототип дружественной функции
friend void inpstr(MyStr&, int );
public:
static int num; // счетчик порядкового номера
int nn; // порядковый номер строки
…
}; // конец определения класса
int MyStr::count=0;
int MyStr::num=0;
// определение дружественной функции
void inpstr(MyStr& s, int n)
{ char* fs; // указатель для доступа к дин.памяти
fs= new char[n+1]; // получение дин. памяти
cout<<"ввод с клавиатуры:"; // «приглашение» для ввода
cin>>fs;
strcpy(s.buf,fs); // копирование строки в закрытую область объекта класса
}
int main(int argc, char* argv[])
{MyStr c1("1_string"); // создание объекта с1
cout<<endl<<"Объект с1"<<endl;
c1.display();
MyStr c2(c1); // создание объекта с2 (инициализация копированием)
cout<<"Объект с2"<<endl;
c2.display();
MyStr c3=c1; // создание объекта с3 и присвоение ему значения с1
cout<<"Объект с3"<<endl;
c3.display();
cout<<"c1-"; // отображаем объект ввода
inpstr(c1,10); // вызов дружественной функции
cout<<"новый Объект с1"<<endl;
c1.display();
system ("pause");
return 0;
}
До сих пор мы решали задачи с использованием отдельных экземпляров класса, но для создания баз данных необходимы массивы объектов класса.
Создавая массивы объектов, например MyStr V[10], нам потребуется конструктор с инициализацией по-умолчанию. Такой конструктор может выглядеть, например так:
// конструктор по-умолчанию
MyStr()
{ num++; // при создании объекта счетчики наращиваются
count++;
nn=num;
// по-умолчанию выделяется строка под 60 символов
buf= new char[60];
buf="free"; // константная строка
}
Создадим массив из объектов по-умолчанию и распечатаем его в виде таблицы.
class MyStr
{…
// метод для вывода данных объекта в табличном виде
void display_tab()
{ cout<<nn<<'\t'<<buf<<endl;
}
…
}; // конец определения класса
int main(int argc, char* argv[])
{const int n=15;
int i;
// массив объектов, инициализируемых по-умолчанию
MyStr V[n];
// заголовок таблицы
cout<<" п/п \t строка"<<endl;
cout<<"------------------------"<<endl;
// цикл для вывода данных таблицы
for (i=0;i<n;i++) V[i].display_tab();
cout<<"Общее число записей = "<<V[0].get_count()<<endl;
system ("pause");
return 0;
}
Контрольные вопросы
1. Что такое область видимости, применительно к данным-членам класса?
2. Как можно изменить область видимости с помощью ключевых слов?
3. Что такое друзья класса?
4. Сравните характер доступа, предоставленный с помощью ключа public, с доступом, предоставленным с помощью дружественных функций.
5. Статические поля класса, для чего они нужны, чем отличаются от прочих полей класса?
6. Расскажите о копирующем конструкторе по умолчанию.
7. Когда нужно явно задавать копирующий конструктор.