Опубликован: 10.10.2006 | Доступ: свободный | Студентов: 6059 / 460 | Оценка: 4.26 / 3.88 | Длительность: 31:30:00
Лекция 6:

Производные классы

6.6 Контроль доступа

Член класса может быть частным (private), защищенным (protected) или общим (public):

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

Эти правила соответствуют делению обращающихся к классу функций на три вида: функции, реализующие класс (его друзья и члены), функции, реализующие производный класс (друзья и члены производного класса) и все остальные функции.

Контроль доступа применяется единообразно ко всем именам. На контроль доступа не влияет, какую именно сущность обозначает имя. Это означает, что частными могут быть функции-члены, константы и т.д. наравне с частными членами, представляющими данные:

class X {
 private:
   enum { A, B };
   void f(int);
   int a;
 };

 void X::f(int i)
 {
   if (i<A) f(i+B);
   a++;
 }

 void g(X& x)
 {
   int i = X::A; // ошибка: X::A частный член
   x.f(2);       // ошибка: X::f частный член
   x.a++;            // ошибка: X::a частный член
 }

6.6.1 Защищенные члены

Дадим пример защищенных членов, вернувшись к классу window из предыдущего раздела. Здесь функции _draw() предназначались только для использования в производных классах, поскольку предоставляли неполный набор возможностей, а поэтому не были достаточны удобны и надежны для общего применения. Они были как бы строительным материалом для более развитых функций. С другой стороны, функции draw() предназначались для общего применения. Это различие можно выразить, разбив интерфейсы классов window на две части - защищенный интерфейс и общий интерфейс:

class window {
public:
  virtual void draw();
  // ...
protected:
  void _draw();
  // другие функции, служащие строительным материалом
private:
  // представление класса
};

Такое разбиение можно проводить и в производных классах, таких, как window_w_border или window_w_menu.

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

Вот менее практичный, но более подробный пример:

class X {
// по умолчанию частная часть класса
   int priv;
protected:
   int prot;
public:
   int publ;
   void m();
};

Для члена X::m доступ к членам класса неограничен:

void X::m()
{
  priv = 1;   // нормально
  prot = 2;   // нормально
  publ = 3;   // нормально
}

Член производного класса имеет доступ только к общим и защищенным членам:

class Y : public X {
   void mderived();
};

Y::mderived()
{
  priv = 1;    // ошибка: priv частный член
  prot = 2;    // нормально: prot защищенный член, а
   // mderived() член производного класса Y
  publ = 3;    // нормально: publ общий член
}

В глобальной функции доступны только общие члены:

void f(Y* p)
{
  p->priv = 1;  // ошибка: priv частный член
  p->prot = 2;  // ошибка: prot защищенный член, а f()
    // не друг или член классов X и Y
  p->publ = 3;  // нормально: publ общий член
}

6.6.2 Доступ к базовым классам

Подобно члену базовый класс можно описать как частный, защищенный или общий:

class X {
public:
  int a;
  // ...
};

class Y1 : public X {  };
class Y2 : protected X { };
class Y3 : private X { };

Поскольку X - общий базовый класс для Y1, в любой функции, если есть необходимость, можно (неявно) преобразовать Y1* в X*, и притом в ней будут доступны общие члены класса X:

void f(Y1* py1, Y2* py2, Y3* py3)
{
  X* px = py1;  // нормально: X - общий базовый класс Y1
  py1->a = 7;   // нормально
  px = py2;     // ошибка: X - защищенный базовый класс Y2
  py2->a = 7;   // ошибка
  px = py3;     // ошибка: X - частный базовый класс Y3
  py3->a = 7;   // ошибка
}

Теперь пусть описаны

class Y2 : protected X { };
class Z2 : public Y2 { void f(); };

Поскольку X - защищенный базовый класс Y2, только друзья и члены Y2, а также друзья и члены любых производных от Y2 классов (в частности Z2 ) могут при необходимости преобразовывать (неявно) Y2* в X*. Кроме того они могут обращаться к общим и защищенным членам класса X:

void Z2::f(Y1* py1, Y2* py2, Y3* py3)
{
  X* px = py1; // нормально: X - общий базовый класс Y1
  py1->a = 7; // нормально
  px = py2;   // нормально: X - защищенный базовый класс Y2,
  // а Z2 - производный класс Y2
  py2->a = 7; // нормально
  px = py3;   // ошибка: X - частный базовый класс Y3
  py3->a = 7; // ошибка
}

Наконец, рассмотрим:

class Y3 : private X { void f(); };

Поскольку X - частный базовый класс Y3, только друзья и члены Y3 могут при необходимости преобразовывать (неявно) Y3* в X*. Кроме того они могут обращаться к общим и защищенным членам класса X:

void Y3::f(Y1* py1, Y2* py2, Y3* py3)
{
  X* px = py1;  // нормально: X - общий базовый класс Y1
  py1->a = 7;   // нормально
  px = py2;     // ошибка: X - защищенный базовый класс Y2
  py2->a = 7;   // ошибка
  px = py3;     // нормально: X - частный базовый класс Y3,
    // а Y3::f член Y3
  py3->a = 7;   // нормально
}
Дарья Федотова
Дарья Федотова
Сергей Березовский
Сергей Березовский

В рамках проф. переподготовки по программе "Программирование"

Есть курсы, которые я уже прошел. Но войдя в курс я вижу, что они не зачтены (Язык Ассемблера и архитектура ЭВМ, Программирование на С++ для профессионалов). Это как?

Алексей Иевенко
Алексей Иевенко
Украина, Великая Михайловка