Страницы

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

воскресенье, 15 марта 2020 г.

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

#cpp #классы


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

// файл 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);
};

    


Ответы

Ответ 1



Не получается потому, что для объявления дружественного метода требуется полное определение 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.

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

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