Страницы

Поиск по вопросам

среда, 5 июня 2019 г.

Дружественная функция из другого класса

Не могу разобраться, как прописать классу дружественную функцию из другого класса. Проблема в том, что классы написаны в разных файлах. Вот код:
// файл Complex.h #include "Float.h" class Complex { private: Float Re, Im; public: Complex(Float re, Float im); void readFloat(Float); }; // файл Complex.cpp #include "Complex.h" #include using namespace std; void Complex::readFloat(Float) { cout << "Чтение из дружественной функции: " << Re.Num; } // файл Float.h class Float { private: float Num; public: Float(float num); friend void Complex::readFloat(Float); };


Ответ

Не получается потому, что для объявления дружественного метода требуется полное определение Complex, ведь вы обращаетесь к его члену.
Самый простой вариант - сделать другом не метод, а весь класс Complex
// файл Float.h class Float { private: float Num; public: Float(float num); friend class Complex; };
Если, всеж таки, необходим именно дружественный метод, тогда нужно обеспечить чтобы полное определение Complex гарантированно происходило до определения Float. Это можно сделать, применив технику с предварительным объявлением (forward declaration) Float в файле Complex.h:
// файл Complex.h // #include "Float.h" // этот инклюд нужно убрать
class Float; // предварительное объявление
class Complex { private: Float * Re; Float * Im;
public: Complex(Float & re, Float & im); ~Complex();
void readFloat(Float &); };
// файл Complex.cpp #include
#include "Complex.h" #include "Float.h" // а здесь он нужен
void Complex::readFloat(Float&) { std::cout << "Чтение из дружественной функции: " << Re.Num; }
// файл Float.h #include "Complex.h" // мы обращаемся к членам Complex // поэтому он должен быть объявлен заранее class Float { private: float Num; public: Float(float num); friend void Complex::readFloat(Float&); };
Техника работает следующим образом. Так как в файле Complex.h используются только указатели и ссылки на Float компилятору для вычисления размеров этих переменных и полей не требуется полное определение класса Float. Ведь размер указателей и ссылок фиксированный и заранее известен, вне зависимости от того, на что они указывают или ссылаются. Компилятору нужно только намекнуть что понимается под именем Float то есть что он класс, а не структура например. Компилятор не может работать с неизвестными именами. Из-за этой тонкости, можно убрать #include "Float.h" из файла Complex.h. Однако, когда мы обращаемся к членам Float необходимо его полное определение, поэтому в файле Complex.cpp обязательно наличие #include "Float.h". После всего этого можно безопасно добавлять #include "Complex.h" в файле Float.h.
В результате всех этих манипуляций получается, что класс Complex всегда определен до Float, хотя объявлен Float раньше Complex. Ну и в итоге, как вы помните, строгий порядок определений классов позволяет нам законно объявить дружественным метод Complex::readFloat.

Комментариев нет:

Отправить комментарий