Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

OOP_C++ / 10

.htm
Скачиваний:
20
Добавлен:
02.02.2015
Размер:
13.31 Кб
Скачать

10 - Область видимости класса. Друзья класса Содержание     Предыдущее занятие     Следующее занятие

Занятие 10 Область видимости класса. Друзья класса 1 Область видимости класса Тело класса определяет отдельную область видимости. Объявление элементов внутри тела помещает их имена в область видимости класса.

Для обращения к ним применяются операторы доступа (точка и стрелка) и оператор разрешения области видимости (::). Когда употребляется оператор доступа, то предшествующее ему имя обозначает объект или указатель на объект типа класса, а следующее за ним имя должно находиться в области видимости этого класса. Аналогично при использовании оператора разрешения области видимости поиск имени, следующего за ним, идет в области видимости класса, имя которого стоит перед оператором.

class X { int i; public: void f() { int i; i = X::i; } }; В реализации функции переменная i переопределяет имя элемента данных класса. Теперь для доступа к элементу данных i необходимо использовать операцию классовой области видимости.

Функция-элемент входит в область видимости своего класса. Кроме того, у нее есть своя локальная область видимости.

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

class X { public: class Y { public: int t; }; private: class Z { public: int w; }; Z z; // Элемент данных типа вложенного класса }; X::Y y; // Объект класса Y X::Z z; // Ошибка: класс Z недоступен Класс, входящий в локальную область видимости, называется локальным классом. Он может определяться либо в функции-элементе, либо в обычной функции.

2 Статические элементы класса Спецификатор static может быть использован для описания элементов данных и функций-элементов. Такие элементы называются статическими. В отличие от обычных элементов данных, копия которых имеется в каждом объекте класса, для всего класса существует только одна копия статических элементов данных. Доступ к таким данным может осуществляться как через имя объекта, так и без использования конкретного экземпляра объекта:

class X  { . . . public:     static int i; }; . . . X::i = 10; // Через имя класса X x; x.i = 11; // Через имя объекта как видно из примера, для обращения к статическому элементу данных, объект данного класса может не существовать.

Существуют также статические функции-элементы.

Поскольку статические функции-элементы могут вызываться без какого-либо объекта класса, они не получают указателя this и, следовательно, не имеют доступа ни к одному из нестатических элементов.

В одном классе нельзя иметь статическую и нестатическую функции-элементы с одинаковыми именами и списками параметров.

Описание статических элементов в классе есть объявление, но не определение. Следовательно, где-то в другом месте в программе должно быть осуществлено их определение для выделения памяти и инициализации. Статические элементы класса, локально объявленного в функции, не могут быть проинициализированы. Статические элементы класса в глобальной области видимости могут быть определены и проинициализированы как обычные глобальные объекты файловой области видимости. Статические элементы вложенных классов тоже должны быть проинициализированы в файловой области видимости.

class X  { static int x; static const int size = 5; class Inner  // Вложенный класс { static float f; void func(void);       }; public: char array[size]; }; int X::x = 1; // Определение и инициализация float X::Inner::f = 3.14; // инициализация статического // элемента вложенного класса void X::Inner::func(void)  {      // Определение функции вложенного класса } Основное использование статических элементов заключается в представлении данных, общих для всех объектов данного класса, таких как количество созданных объектов и т. д. Статические элементы также используются для сокращения количества общедоступных глобальных имен и определения логической принадлежности к конкретным классам.

3 Друзья класса Друг F класса X - это обычная функция или класс, имеющие полные права доступа к закрытым (private) и защищенным (protected) элементам класса X.

Друзья класса не входят в классовую область видимости и не являются элементами класса X. Обращение к F не может быть реализовано как x.F для объекта x класса X.

Дружественные функции, определенные внутри класса, имеют неявный модификатор inline.

Описание друзей класса может быть произведено в любой части класса (public, private или protected). Это никак не влияет на доступ к дружественным функциям и классам.

class X { int i; // закрытый элемент X friend void friend_func(X*, int); // Функция не является закрытой public: void member_func(int); }; // Обе функции имеют доступ к i: void friend_func(X* xptr, int a)  {  xptr–>i = a;  } void X::member_func(int a)  {  i = a;  } X xobj; friend_func(&xobj, 6); xobj.member_func(6); Все функции класса Y можно сделать друзьями класса X одним определением:

class Y;             // объявление класса class X  {     friend Y;     int i;     void member_funcX(); }; class Y {                    // определение класса   void friend_X1(X&);     void friend_X2(X*); . . . }; В данном примере функции, объявленные в Y, являются друзьями X, как если бы они имели спецификации friend. Они могут обращаться к закрытым элементам класса X, таким как i и member_funcX.

Можно также отдельные функции-элементы класса X объявить другом класса Y:

class X  { . . .     void member_funcX(); }; class Y  { friend void X::member_funcX(); . . . }; Дружба классов на транзитивна: если X является другом Y, а Y - друг Z, это не означает, что X является другом Z. Дружба не наследуется.

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

#include <iostream> using namespace std; class SomeClass { static int count; // Счетчик int k; public: SomeClass() { count++; } SomeClass(int k) { this->k = k; count++; } SomeClass(const SomeClass& sc) { k = sc.k; count++; } ~SomeClass() { count--; } static int getCount() { return count; } }; int SomeClass::count = 0; // Инициализация статического элемента void main() { cout << SomeClass::getCount() << endl; // Вызов через имя класса SomeClass sc1; cout << sc1.getCount() << endl; // Вызов через имя объекта SomeClass sc2(6); cout << SomeClass::getCount() << endl; SomeClass sc3 = sc2; cout << SomeClass::getCount() << endl; SomeClass *psc = new SomeClass(); cout << psc->getCount() << endl; // Вызов через указатель delete psc; cout << SomeClass::getCount() << endl; } 4.2 Использование статических функций Иногда глобальные функции целесообразно группировать в классы, используя классы в качестве пространств имен. Например, можно реализовать класс, содержащий функции square() и cube(). Для вызова этих функций можно было бы создать объект класса, но целесообразнее воспользоваться операцией разрешения области видимости:

#include <iostream> using namespace std; class Math { public: static double square(double x) { return x * x; } static double cube(double x); }; double Math::cube(double x) { return x * x * x; } void main() { double x; cin >> x; cout << Math::square(x) << " " << Math::cube(x) << endl; } 4.3 Использование друзей класса Ранее решенную задачу сравнения двух точек можно реализовать с использованием функции-друга класса:

class Point { friend bool isEqual(Point& p1, Point& p2); private: double x, y; public: Point(double newX, double newY) { x = newX; y = newY; } }; bool isEqual(Point& p1, Point& p2) { return (&p1 == &p2) || (p1.x == p2.x) && (p1.y == p2.y); } int main(int argc, char* argv[]) { Point p1(1, 1), p2(2, 2), p3(1, 1); cout << isEqual(p1, p1) << ' ' << isEqual(p1, p2) << ' ' << isEqual(p1, p3); return 0; } Второй вариант реализации более соответствует смыслу функции, которая логически не может быть отнесена ни к одному из классов.

6 Задание на самостоятельную работу Спроектировать класс Math функциями, вычисляющими произвольную целую степень и квадратный корень. Квадратный корень числа x можно вычислять по следующему алгоритму: задаем первое приближение y0, каждое следующее приближение вычисляем по формуле:

yi+1 = (yi + x/yi)/2

Процесс завершается, когда yi2 отличается от x меньше заданной погрешности.

 

Содержание     Предыдущее занятие     Следующее занятие

 

© 2001 - 2006 Иванов Л.В.

Соседние файлы в папке OOP_C++