logo
Лекции по С++ глава 4

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

Даже если класс CBlock наследует переменные-члены Left, Top, Right и Bottom из своего базового класса, это не означает возможности прямого доступа, так как они определены в базовом классе как закрытые. Вместо этого пришлось бы использовать открытую функцию GetCoord, как и в остальной части программы. Такое ограничение приводит к тому, что код функций-членов становится в определенной степени неэффективным. В качестве альтернативы можно указать спецификатор доступа protected вместо private (листинг 4.1).

Листинг 4.1

// CRectl.h: файл заголовков класса CRectangle

class CRectangle

{

protected:

int Left,

int Top;

int Right;

int Bottom;

public:

CRectangle ()

{

Left = Top = Right = Bottom = 0;

}

CRectangle {int L, int T, int R, int B)

{

SetCoord (L, T, R, B);

}

void Draw (void);

void GetCoord (int *L, int *T, int *R, int *B)

{

*L = Left;

*T = Top;

*R = Right;

*B = Bottom;

}

void SetCoord (int L, int T, int R, int B);

};

Напомним: в данной версии класса CRectangle предполагается определение методов Draw и SetCoord вне класса. Подобно закрытым членам, к защищенным членам класса доступ извне невозможен. Приведенный ниже способ обращения к переменной является некорректным.

void main ( )

{

CRectangle Rect;

Rect.Left =10; // ОШИБКА: доступ к защищенному

// члену класса невозможен

}

Однако в отличие от закрытых к защищенным членам класса можно непосредственно обращаться из класса, производного от того класса, в котором данная переменная определена. Следовательно, CBlock можно переписать, используя прямой доступ к переменным-членам, определенным в CRectangle (листинг 4.2).

Листинг 4.2

// CBlock.h: файл заголовков класса CBlock

#include "crectl.h"

#include <stdlib.h>

void Fill (int X, int Y, int Color);

class CBlock: public CRectangle

{

protected:

int FillColor;

public:

CBlock()

{

FillColor = 0;

}

CBlock (int L, int T, int R, int B, int Color)

: CRectangle {L, T, R, B)

{

SetColor (Color);

}

void Draw (void)

{

CRectangle::Draw ( );

Fill ((Left + Right)/2, (Top + Bottom)/2, FillColor);

}

void SetColor (int Color)

{

FillColor = _max (0, Color) ;

}

};

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

Можно предоставить другому классу или глобальной функции доступ к внутренним или защищенным членам класса, объявив его или функцию дружественными (friend) для данного класса. Этот прием описан в гл. 5 «Перегрузка оператора присваивания».

Наследования открытого и закрытого типа

Если класс порожден с использованием спецификатора public

class CBlock: public CRectangle

{

// определение класса ...

}

то открытые члены базового класса остаются открытыми, а защищенные – защищенными и в производном классе.

Однако если для определения производного класса использован спецификатор private

class CBlock : private CRectangle

{

// определение класса ...

}

то все закрытые и защищенные члены базового класса становятся закрытыми членами производного класса. Если при определении производного класса спецификатор не задан, то по умолчанию он определяется как закрытый.

Независимо от способа наследования, закрытые члены базового класса недоступны для производного (несмотря на то, что они наследуются производным классом и являются частью любого экземпляра производного класса, прямой доступ к ним из производного класса невозможен).

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