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

2. Доступ к наследуемым компонентам

Доступность различных составляющих (компонентов) класса в производном классе определяется соответствующим ключем доступа, задаваемым словами private, public или protected.

Частный (private) компонент класса доступен только другим компонентам и друзьям этого класса, тогда как общий (public) компонент доступен и вне данного класса. Частные компоненты базового класса для производных классов являются недоступными.

Программист может позволить производным классам доступ к конкретным компонентам базового. C++ имеет также третью категорию доступности компонентов класса, называемую защищенной (protected). Защищенные компоненты недоступны ни для каких частей программы, за исключением компонентов производных классов.

Класс может быть унаследован как public или как private. При этом модификатор private трансформирует компоненты базового класса с атрибутами доступа public и protected в компоненты private производного класса, в то время как private-компоненты становятся недоступны в производном классе.

Модификатор наследования public не изменяет уровня доступа. Производный класс наследует все компоненты своего базового класса, но может использовать только те из них, которые определены с атрибутами public и protected.

Разные типы наследования влияют только на доступ по умолчанию компонентов базового класса в производном классе. Правила наследования доступа показаны в табл.4.1.

Таблица 4.1

Доступ

наследования

Доступ

компонентов в

базовом классе

Доступность компонентов

базового класса в

производном классе

public

public

protected

private

public

protected

недоступен

private

public

protected

private

private

private

недоступен

При объявлении класса-потомка с помощью ключевого слова class статусом доступа по умолчанию является private, а при объявлении с помощью ключевого слова struct - public, то есть

struct D: B{... }; означает: struct D: public B{ public:...};

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

class Level0 { // Базовый класс

private: int a;

protected: int b;

public: int c;

int e;

void f0();

};

class Level1a: public Level0 {

protected: int d;

public: int f;

void f1();

};

// Обычная функция - имеет доступ только к public-компонентам

void fn() {

Level0 L0;

Level1a L1;

L0.e = 1; // public-компонент

L1.e = 1; // public-компоненты из Level0 являются

// также public и в Level1a

L1.f = 2;

L1.f0();

L1.f1();

}

// Компонентные функции

void Level0::f0() { // имеет доступ ко всему Level0

a = 1;

b = 2;

c = 3;

}

void Level1a::f1() {

b = 1; // доступа к a не имеет

c = 2;

d = 3; // имеет доступ ко всему Level1a

e = 4;

f = 5;

f0();

}

В следующих частных производных классах L1.c и L1.f0() внешней функции fn() не доступны, поскольку они являются частными, хотя L0.c и L0.f0() продолжают оставаться доступными. Доступность компонентов для компонентных функций f0() и f1() остается неизменной.

class Level1b: private Level0 {

private: int d;

protected: int e;

public: int f;

void f1();

};

class Level1c: Level0 { // аналогично Level1b

private: int d;

protected: int e;

public: int f;

void f1();

};

// Общая функция

void fn() {

Level0 L0;

Level1b L1;

L0.c = 1;

L0.f0();

L1.f = 1; // доступа к L1.c или L1.f0() теперь нет

L1.f1();

}

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

class Level1d: private Level0 {

public:

Level0::c; // конкретно объявляет переменную c как public

int f;

void f1();

};

// Общая функция

void fn() {

Level0 L0;

Level1d L1;

L0.c = 1;

L0.f0();

L1.c = 1; // доступ к c теперь возможен, но

// f0 остается недоступной

L1.f = 2;

L1.f1();

}

При объявлении Level1d как private-производного умолчание для доступности переменной c изменяется с public на private. Однако, объявив специальным образом переменную c как public, умолчание можно переопределить, делая L1.c доступной из обычной функции fn(). Level1d не может обеспечить сам себе доступ к компоненту a, который является частным (private) в базовом классе.