Дружественные функции - зачем они нужны?

Рейтинг: 3Ответов: 1Опубликовано: 11.11.2014

Только что с ними разобрался, но не вижу их применения. Где их применяют?

Ответы

▲ 2Принят

Дружественные функции чаще всего не нужны и даже вредны, т. к. они разрушают инкапсуляцию. Однако иногда всё-таки без нарушения инкапсуляции трудно.

Классический пример — бинарный оператор. Хорошим тоном является определение бинарного оператора как внешней статической функции. Для того, чтобы эффективнее вычислять значение, оператору может понадобиться доступ «внутрь» класса, так что его приходится объявлять friend'ом.

Пример:

class YetAnotherString
{
    char* m_data;
    int m_length, m_capacity;

    YetAnotherString(int length)
    {
        m_length = length;
        PrepareBuffer();
    }

    void PrepareBuffer()
    {
        m_capacity = ((m_length + 31) / 32) * 32 // выровнять на 32 байта
        m_data = new char[m_capacity + 1];
    }

  public:
    YetAnotherString(const char* data)
    {
        m_length = strlen(data);
        PrepareBuffer();
        strcpy(m_data, data);
    }
    int GetLength() { return m_length; }
    char* GetCStr() { return m_data; }
    // тут ещё оператор присваивания, копирующий конструктор
    // и деструктор
    friend operator + (char* raw, const YetAnotherString& string);
};

YetAnotherString operator + (char* raw, const YetAnotherString& string)
{
    int lhsLength = strlen(raw);
    int rhsLength = string.GetLength();
    // мы хотим избежать ненужного копирования в конструкторе YetAnotherString
    // поэтому пользуемся приватным конструктором
    // без friend-декларации это бы не скомпилировалось
    YetAnotherString result(lhsLength + rhsLength);
    strcpy(result.m_data, raw);
    strcpy(result.m_data + lhsLength, string.GetCStr());
    return result;
}