<< Предыдущая Оглавление Следующая >>


6.3. Дружественные классы и функции

В рассмотренных примерах наследования функция Draw() дочерних классов использует переменные sp_x, sp_y, ep_x, ep_y, width и color базовых классов, которые необходимо было объявлять в разделе protected. Вместе с тем лучшую защиту этих переменных можно обеспечить, объявив их частными (private). Но тогда при наследовании они оказываются недоступными в производных классах, а реализация функции Draw() невозможной. Чтобы разрешить эту проблему, дочерние классы, использующие частные переменные базовых классов, необходимо объявить как дружественные к соответствующим базовым.

Для объявления дружественного класса используется ключевое слово friend, за которым следует имя класса. Следующий пример демонстрирует объявление дружественного класса CLine классам CPos и CProp:

class CLine; //идентификатор класса

class CPos
{
protected:
CPos() {}
CPos(int x1, int y1, int x2, int y2) {SetParam(x1,y1,x2,y2);}
~CPos() {}

public:
friend CLine; //объявление дружественного класса

void SetParam(int x1, int y1, int x2, int y2);

protected:
int sp_x, sp_y;
int ep_x, ep_y;
};

class CProp
{
protected:
CProp() {}
CProp(int wdt, int clr) {SetProperty(wdt,clr);}
~CProp();

public:
friend CLine; //объявление дружественного класса

void SetProperty(int wdt, int clr);

protected:
int width, color;
};

В данном примере класс CLine является производным от классов CPos и CProp, поэтому он объявляется после них. Однако, чтобы сделать класс CLine дружественным базовым классам он должен быть объявлен до них, иначе компилятор С++ выдаст синтаксическую ошибку. Чтобы разрешить эту проблему язык С++ допускает использование идентификатора класса, который говорит компилятору о том, что такой класс есть, но его описание будет дано ниже. Благодаря этому удается организовать перекрестные ссылки между классами, стоящие на разных уровнях иерархии. В результате такой организации частные элементы sp_x, sp_y, ep_x, ep_y, width и color классов CPos и CProp оказываются доступными только одному производному классу CLine и никакому другому, что обеспечивает их лучшую защиту по сравнению с уровнем доступа protected.

Дружественными можно объявлять не только классы, но и отдельные функции классов. Например, для класса CLine важно, чтобы переменные sp_x, sp_y, ep_x, ep_y, width и color были доступны только функции Draw(). Поэтому было бы целесообразно ее и сделать дружественной, а не весь класс целиком. Однако для этого потребовалось бы ее прототип описать до классов CPos и CProp, что сделать в данном случае невозможно, т.к. класс CLine, в котором находится функция Draw(), описан в последнюю очередь. Но, в общем, дружественные функции можно задавать, как показано в следующем фрагменте программы:

class CPos;
class CLine
{
public:
CLine() {}
~CLine() {}

void Draw(CPos* pos);
};

class CPos
{
public:
CPos() {}
~CPos() {}

friend void CLine::Draw(CPos* pos);

private:
int sp_x, sp_y;
int ep_x, ep_y;
};

void CLine::Draw(CPos* pos)
{
MoveTo(pos->sp_x, pos->sp_y);
LineTo(pos->ep_x, pos->ep_y);
}

Особенностью организации классов CLine и CPos является то, что функция Draw() класса CLine использует в качестве аргумента указатель на класс CPos, который объявлен ниже. Поэтому реализации функции Draw() должна быть объявлена после определения класса CPos, иначе компилятор С++ выдаст сообщение об ошибке. Благодаря тому, что функция Draw() является дружественной классу CPos, она может получать доступ к частным элементам этого класса через переданный ей указатель.


<< Предыдущая Оглавление Следующая >>