Void Vec :: EndVec ( const Dot & A , Dot & B ) // описание функции-члена класса Vec
Дружественной классу Vec
Include "DotVec.h" // подключение заголовочного файла DotVec
Friend void Dot :: EndVec ( const Dot & A , const Vec & AB ) ; // объявление дружественной функции
Void EndVec ( const Dot & A , Dot & B ) ; // объявление функции-члена класса
Class Vec // класс вектора
Void EndVec ( const Dot & A , const Vec & AB ) ; // объявление функции-члена класса
Class Dot // класс точки
Class Vec ; // неполное объявление класса вектора
EndVec ( A , AC , C ) ; // вызов дружественной функции
Include "DotVec.h" // подключение заголовочного файла DotVec
Void EndVec ( const Dot & A , const Vec & AB , Dot & B ) // описание дружественной функции
Void Vec :: EndVec ( const Dot & A , Dot & B ) // описание функции-члена класса Vec
Void Dot :: EndVec ( const Dot & A , const Vec & AB ) // описание функции-члена класса Dot
Три функции вычисляют координаты конца заданного вектора
Include "DotVec.h" // подключение заголовочного файла DotVec
Объявление дружественной функции
Void EndVec ( const Dot & A , Dot & B ) ; // функция-член класса Vec
Вычисляет координаты конца заданного вектора
Vec ( char * pName , Dot A , Dot B ) ; // конструирование вектора по координатам его концов
Конструкторы класса Vec
Double x , y ; // проекции вектора
Char name [ 3 ] ; // имя вектора
Class Vec // класс вектора
Объявление дружественной функции
Void EndVec ( const Dot & A , const Vec & AB ) ; // функция-член класса Dot
Вычисляет координаты конца заданного вектора
Double x , y ; // координаты точки
Const char name ; // имя точки
Class Dot // класс точки
Class Vec ; // неполное объявление класса вектора
Include<math.h> // содержит математические функции
Include<windows.h> // содержит функцию CharToOem
Include<iostream.h> // содержит функции ввода-вывода
{
public:
Dot ( char Name ) : name ( Name ) { x = 0 ; y = 0 ; }
Dot ( char Name , double X , double Y ) : name ( Name ) { x = X ; y = Y ; }
inline double GetX ( ) const { return x ; }
inline double GetY ( ) const { return y ; }
inline void SetX ( double X ) { x = X ; }
inline void SetY ( double Y) { y = Y ; }
friend void EndVec ( const Dot & A , const Vec & AB , Dot & B ) ;
• • •
} ;
{
public:
Vec ( char * pName ) { strncpy ( name , pName , 3 ) ; x = 0 ; y = 0 ; }
Vec ( char * pName , double X , double Y ) { strncpy ( name , pName , 3 ) ; x = X ; y = Y ; }
double GetX ( ) const { return x ; }
double GetY ( ) const { return y ; }
friend void EndVec ( const Dot & A , const Vec & AB , Dot & B ) ;
• • •
} ;
Файл DotVec.cpp
{
x = A.x + AB.GetX ( ) ;
y = A.y + AB.GetY ( ) ;
}
{
B.SetX ( A.GetX ( ) + x ) ;
B.SetY ( A.GetY ( ) + y ) ;
}
{
B.x = A.x + AB.x ;
B.y = A.y + AB.y ;
}
Файл Main.cpp
void main ( )
{
Dot A ('A', 3 , 4 ) , B ('B',-3 , 4 ) ; // вызов конструктора Dot ( char Name , double X , double Y )
Dot C ('C') , D ('D') ; // вызов конструктора Dot ( char Name )
Vec AB ("AB", A , B ) ; // вызов конструктора Vec ( char * pName , Dot A , Dot B )
Vec AC ("AC", 2 , 2 ) ; // вызов конструктора Vec ( char * pName , double X , double Y )
C.EndVec ( A , AC ) ; // вызов функции Dot :: EndVec ( const Dot & A , const Vec & AB )
AC.EndVec ( A , C ) ; // вызов функции Vec :: EndVec ( const Dot & A , Dot & B )
} // EndVec ( const Dot & A , const Vec & AB , Dot & B )
Эта программа демонстрирует важный случай применения неполного объявления класса: без применения этой конструкции в данном случае было бы невозможно объявить дружественную функцию для двух классов. Неполное объявление класса Vec дает возможность использовать его имя в объявлении дружественной функции еще до то определения. Необходимо отметить, что при неполном объявлении класса объявления классов должны находиться в одном заголовочном файле, в данном случае DotVec.h.
В приведенном примере объявлены классы точки Dot и вектора Vec и поставленная задача решена тремя различными способами.
Функция void Dot :: EndVec ( const Dot & A , const Vec & AB ) является членом класса Dot, получает константные ссылки на вектор и начало вектора и передаёт координаты конца вектора в текущую точку. Поскольку закрытые члены-данные класса Vec недоступны в классе Dot, то мы используем открытые функции-члены класса Vec – GetY ( ) и GetX ( ). Функция-член класса вызывается оператором: C.EndVec ( A , AC ), где объект C является текущим, а объекты A и AC – параметрами.
Функция void Vec :: EndVec ( const Dot & A , Dot & B ) является членом класса Vec, получает константную ссылку на начало вектора и ссылку на конец вектора. При вычислениях используются значения проекций текущего вектора. Поскольку закрытые члены-данные класса Dot недоступны в классе Vec, то мы используем открытые функции-члены класса Dot – GetX ( ), GetY ( ), SetX ( ), SetY ( ). Функция-член класса вызывается оператором: AC.EndVec ( A , C ), где объект AC является текущим, а объекты A и C – параметрами.
Функция friend void EndVec ( const Dot & A , const Vec & AB , Dot & B ) является дружественной классам Dot и Vec. Для этого она объявлена в обоих классах с ключевым словом friend. Функция получает константные ссылки на начало вектора и вектор, а также ссылку на конец вектора. Поскольку закрытые данные-члены обоих классов Dot и Vec доступны дружественной функции, то мы используем оператор “точка” для доступа к этим данным. Дружественная функция вызывается оператором EndVec ( A , AC , C ).
Функции-члены, дружественные другому классу
Функция может быть членом одного класса и дружественной другому классу. Для демонстрации этого синтаксического приёма немного изменим предыдущий пример:
Файл DotVec.h
{
• • •
public:
} ;
{
• • •
public:
} ;
Файл DotVec.cpp
void Dot :: EndVec ( const Dot & A , const Vec & AB ) // описание функции-члена класса Dot,
x = A.x + AB.x ;
y = A.y + AB.y ;
}
{
B.SetX ( A.GetX ( ) + x ) ;
B.SetY ( A.GetY ( ) + y ) ;
}
Функция void Dot :: EndVec ( const Dot & A , const Vec & AB ) является членом класса Dot, но её прототип с ключевым словом friend включён также в объявление класса Vec. Таким образом, эта функция является дружественной классу Vec. Поскольку закрытые данные-члены класса Vec доступны дружественной функции, то мы используем оператор “точка” для доступа к данным-членам объекта типа Vec.
Следует отметить, что класс, дружественный функции, должен быть полностью объявлен ранее. Нам не удалось сделать функцию void Vec :: EndVec ( const Dot & A , Dot & B ) дружественной классу точки Dot, поскольку класс вектора Vec полностью объявлен позже полного объявления класса точки Dot.
Вызов приведённых функций не отличается от предыдущего примера.
ДРУЖЕСТВЕННЫЕ КЛАССЫ
C++ позволяет объявить не только дружественную функцию, но и дружественный класс, предоставив ему полный доступ к членам своего класса. Для этого достаточно включить в объявление класса имя другого класса, объявляемого дружественным, перед которым ставится ключевое слово friend. Например: