Когда вы должны использовать «друг» в C ++?

c++ oop encapsulation friend

162565 просмотра

30 ответа

5542 Репутация автора

Я читал часто задаваемые вопросы по C ++ и мне было интересно узнать об этом friendобъявлении. Лично я никогда не использовал это, однако я заинтересован в изучении языка.

Что является хорошим примером использования friend?


Чтение FAQ немного дольше мне нравится идея << >>перегрузки и добавления операторов в друзья этих классов. Однако я не уверен, как это не нарушает инкапсуляцию. Когда эти исключения могут оставаться в рамках строгости ООП?

Автор: roo Источник Размещён: 20.08.2008 05:29

Ответы (30)


0 плюса

8031 Репутация автора

When implementing tree algorithms for class, the framework code the prof gave us had the tree class as a friend of the node class.

It doesn't really do any good, other than let you access a member variable without using a setting function.

Автор: Ryan Fox Размещён: 20.08.2008 05:33

324 плюса

51331 Репутация автора

Решение

Во-первых (ИМО) не слушайте людей, которые говорят, что friendэто бесполезно. Это полезно. Во многих ситуациях у вас будут объекты с данными или функциями, которые не предназначены для публичного доступа. Это особенно верно для больших кодовых баз со многими авторами, которые могут только поверхностно знакомы с различными областями.

Существуют альтернативы спецификатору друга, но часто они громоздки (конкретные классы уровня cpp / маскированные определения типов) или не защищены от ошибок (комментарии или соглашения о именах функций).

На ответ;

Спецификатор friendразрешает назначенному классу доступ к защищенным данным или функциям в классе, делающем оператор Friend. Например, в приведенном ниже коде любой может попросить ребенка назвать свое имя, но только мать и ребенок могут изменить имя.

Вы можете продолжить этот простой пример, рассмотрев более сложный класс, такой как Window. Вполне вероятно, что в Window будет много элементов функций / данных, которые не должны быть общедоступными, но необходимы для связанного класса, такого как WindowManager.

class Child
{
//Mother class members can access the private parts of class Child.
friend class Mother;

public:

  string name( void );

protected:

  void setName( string newName );
};
Автор: Andrew Grant Размещён: 20.08.2008 05:48

1 плюс

9285 Репутация автора

The tree example is a pretty good example : Having an object implemented in a few different class without having an inheritance relationship.

Maybe you could also need it to have a constructor protected and force people to use your "friend" factory.

... Ok, Well frankly you can live without it.

Автор: fulmicoton Размещён: 20.08.2008 05:51

8 плюса

3088 Репутация автора

Вы контролируете права доступа для участников и функций, используя частное / защищенное / публичное право? поэтому, если предположить, что идея каждого из этих трех уровней ясна, тогда должно быть ясно, что мы что-то упустили ...

Объявление члена / функции как защищенного, например, довольно общее. Вы говорите, что эта функция недоступна для всех (за исключением наследственного ребенка, конечно). Но как насчет исключений? каждая система безопасности позволяет вам иметь некоторый тип «белого списка», верно?

Таким образом, друг позволяет вам иметь гибкую изоляцию твердого объекта, но позволяет создать «лазейку» для вещей, которые вы считаете оправданными.

Я думаю, что люди говорят, что это не нужно, потому что всегда есть дизайн, который будет обходиться без него. Я думаю, что это похоже на обсуждение глобальных переменных: вы никогда не должны их использовать, всегда есть способ обойтись без них ... но в действительности вы видите случаи, когда это оказывается (почти) самым элегантным способом. .. Я думаю, что это то же самое с друзьями.

Это на самом деле не приносит никакой пользы, кроме того, что позволяет вам получить доступ к переменной-члену без использования функции настройки

хорошо, что это не совсем способ смотреть на это. Идея состоит в том, чтобы контролировать ВОЗ, которая может получить доступ к тому, что наличие или отсутствие функции настройки имеет мало общего с ней.

Автор: csmba Размещён: 20.08.2008 06:10

27 плюса

184545 Репутация автора

Канонический пример - перегрузка оператора <<. Другим распространенным применением является предоставление доступа к вашим внутренним компонентам помощникам или администраторам.

Вот несколько рекомендаций, которые я слышал о друзьях C ++. Последний особенно запоминающийся.

  • Ваши друзья не друзья вашего ребенка.
  • Друзья вашего ребенка не ваши друзья.
  • Только друзья могут касаться ваших личных частей.
Автор: Mark Harrison Размещён: 20.08.2008 07:05

41 плюса

422793 Репутация автора

@roo : Инкапсуляция здесь не нарушена, потому что сам класс диктует, кто может получить доступ к своим закрытым членам. Инкапсуляция может быть нарушена только в том случае, если это может быть вызвано извне класса, например, если вы operator <<объявите «Я друг класса foo».

friendзаменяет использование public, а не использование private!

На самом деле, C ++ FAQ отвечает уже на это .

Автор: Konrad Rudolph Размещён: 20.08.2008 07:16

-1 плюса

87365 Репутация автора

Вы могли бы придерживаться самых строгих и чистых принципов ООП и гарантировать, что ни один элемент данных для какого-либо класса даже не имеет средств доступа, поэтому все объекты должны быть единственными, которые могут знать о своих данных, и единственный способ воздействовать на них - через косвенные сообщения , т.е. методы.

Но даже в C # есть ключевое слово внутренней видимости, а у Java есть доступность на уровне пакета по умолчанию для некоторых вещей. На самом деле C ++ приближается к идеалу ООП, минимизируя компромисс видимости в классе, указывая точно, какой другой класс и только другие классы могут его видеть.

Я на самом деле не использую C ++, но если бы у C # были друзья, я бы это использовал вместо внутреннего модификатора сборки , который я действительно часто использую. На самом деле это не нарушает инкапсуляцию, потому что единица развертывания в .NET - это сборка.

Но есть и атрибут InternalsVisibleTo (otherAssembly), который действует как механизм друзей перекрестной сборки . Microsoft использует это для сборок визуального конструктора .

Автор: Mark Cidade Размещён: 20.08.2008 07:46

3 плюса

5700 Репутация автора

Чтобы сделать TDD много раз, я использовал ключевое слово «друг» в C ++.

Может ли друг знать обо мне все?


Обновлено: я нашел этот ценный ответ о ключевом слове "друг" с сайта Бьярна Страуструпа .

«Друг» - это явный механизм предоставления доступа, как и членство.

Автор: popopome Размещён: 20.08.2008 08:32

1 плюс

5542 Репутация автора

To do TDD many times I've used 'friend' keyword in C++.
Can a friend know everything about me?

No, its only a one way friendship :`(

Автор: roo Размещён: 20.08.2008 09:19

1 плюс

12784 Репутация автора

One specific instance where I use friend is when creating Singleton classes. The friend keyword lets me create an accessor function, which is more concise than always having a "GetInstance()" method on the class.

/////////////////////////
// Header file
class MySingleton
{
private:
    // Private c-tor for Singleton pattern
    MySingleton() {}

    friend MySingleton& GetMySingleton();
}

// Accessor function - less verbose than having a "GetInstance()"
//   static function on the class
MySingleton& GetMySingleton();


/////////////////////////
// Implementation file
MySingleton& GetMySingleton()
{
    static MySingleton theInstance;
    return theInstance;
}
Автор: Matt Dillard Размещён: 20.08.2008 01:40

2 плюса

0 Репутация автора

Что касается оператора << и оператора >>, то нет веских причин дружить с этими операторами. Это правда, что они не должны быть функциями-членами, но они также не должны быть друзьями.

Лучше всего создавать публичные функции печати (ostream &) и чтения (istream &). Затем напишите оператор << и оператор >> в терминах этих функций. Это дает дополнительное преимущество, позволяя вам сделать эти функции виртуальными, что обеспечивает виртуальную сериализацию.

Автор: Tanton Размещён: 21.08.2008 01:03

5 плюса

824 Репутация автора

Friend полезен, когда вы создаете контейнер и хотите реализовать итератор для этого класса.

Автор: rptony Размещён: 25.08.2008 12:11

153 плюса

8490 Репутация автора

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

Достаточно сказать, что я бы не использовал ключевое слово Friend как важный компонент вашего дизайна.

Автор: Daemin Размещён: 30.08.2008 09:59

3 плюса

501 Репутация автора

У нас была интересная проблема, возникшая в компании, в которой я раньше работал, где мы использовали друга, чтобы оказать достойное влияние. Я работал в нашем фреймворковом отделе, мы создали базовую систему уровня движка над нашей собственной ОС. Внутренне у нас была структура класса:

         Game
        /    \
 TwoPlayer  SinglePlayer

Все эти классы были частью структуры и поддерживаются нашей командой. Игры, производимые компанией, были построены на основе этого фреймворка, созданного одним из детей Игр. Проблема заключалась в том, что у Game были интерфейсы к различным вещам, к которым SinglePlayer и TwoPlayer требовался доступ, но мы не хотели, чтобы они были доступны вне рамок классов. Решение состояло в том, чтобы сделать эти интерфейсы частными и разрешить TwoPlayer и SinglePlayer доступ к ним через дружбу.

По правде говоря, весь этот вопрос мог бы быть решен лучшей реализацией нашей системы, но мы были заперты в том, что имели.

Автор: Ray Размещён: 04.09.2008 11:43

10 плюса

2451 Репутация автора

Еще одна распространенная версия примера Эндрю, страшный код-куплет

parent.addChild(child);
child.setParent(parent);

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

class Parent;

class Object {
private:
    void setParent(Parent&);

    friend void addChild(Parent& parent, Object& child);
};

class Parent : public Object {
private:
     void addChild(Object& child);

     friend void addChild(Parent& parent, Object& child);
};

void addChild(Parent& parent, Object& child) {
    if( &parent == &child ){ 
        wetPants(); 
    }
    parent.addChild(child);
    child.setParent(parent);
}

Другими словами, вы можете уменьшить общедоступные интерфейсы и применять инварианты, которые пересекают классы и объекты в функциях друзей.

Автор: maccullt Размещён: 10.09.2008 02:52

-1 плюса

895 Репутация автора

Друзья также полезны для обратных вызовов. Вы можете реализовать обратные вызовы как статические методы

class MyFoo
{
private:
    static void callback(void * data, void * clientData);
    void localCallback();
    ...
};

где callbackвызовы localCallbackвнутри, и в нем clientDataесть ваш экземпляр. По моему мнению,

или же...

class MyFoo
{
    friend void callback(void * data, void * callData);
    void localCallback();
}

Это позволяет для друга быть определенным чисто в cpp как функция в стиле c, а не загромождать класс.

Точно так же шаблон, который я видел очень часто, состоит в том, чтобы поместить все действительно закрытые члены класса в другой класс, который объявлен в заголовке, определен в cpp и добавлен в список друзей. Это позволяет кодеру скрывать большую часть сложности и внутренней работы класса от пользователя заголовка.

В шапке:

class MyFooPrivate;
class MyFoo
{
    friend class MyFooPrivate;
public:
    MyFoo();
    // Public stuff
private:
    MyFooPrivate _private;
    // Other private members as needed
};

В CPP,

class MyFooPrivate
{
public:
   MyFoo *owner;
   // Your complexity here
};

MyFoo::MyFoo()
{
    this->_private->owner = this;
}

Становится легче скрывать вещи, которые нижестоящему не нужно видеть таким образом.

Автор: shash Размещён: 12.12.2008 12:10

91 плюса

423827 Репутация автора

friendКлючевое слово имеет несколько хороших целей. Вот два вида использования, сразу же видимых для меня:

Определение друга

Определение «друг» позволяет определить функцию в области действия класса, но эта функция будет определяться не как функция-член, а как свободная функция окружающего пространства имен, и обычно не будет видна, за исключением поиска, зависящего от аргумента. Это делает его особенно полезным для перегрузки операторов:

namespace utils {
    class f {
    private:
        typedef int int_type;
        int_type value;

    public:
        // let's assume it doesn't only need .value, but some
        // internal stuff.
        friend f operator+(f const& a, f const& b) {
            // name resolution finds names in class-scope. 
            // int_type is visible here.
            return f(a.value + b.value);
        }

        int getValue() const { return value; }
    };
}

int main() {
    utils::f a, b;
    std::cout << (a + b).getValue(); // valid
}

Частный базовый класс CRTP

Иногда вы обнаруживаете, что политике нужен доступ к производному классу:

// possible policy used for flexible-class.
template<typename Derived>
struct Policy {
    void doSomething() {
        // casting this to Derived* requires us to see that we are a 
        // base-class of Derived.
        some_type const& t = static_cast<Derived*>(this)->getSomething();
    }
};

// note, derived privately
template<template<typename> class SomePolicy>
struct FlexibleClass : private SomePolicy<FlexibleClass> {
    // we derive privately, so the base-class wouldn't notice that, 
    // (even though it's the base itself!), so we need a friend declaration
    // to make the base a friend of us.
    friend class SomePolicy<FlexibleClass>;

    void doStuff() {
         // calls doSomething of the policy
         this->doSomething();
    }

    // will return useful information
    some_type getSomething();
};

Вы найдете необдуманный пример для этого в этом ответе. Другой код, использующий это в этом ответе. База CRTP преобразует этот указатель, чтобы иметь возможность доступа к полям данных производного класса с помощью указателей на элементы-данные.

Автор: Johannes Schaub - litb Размещён: 13.12.2008 03:49

4 плюса

9390 Репутация автора

Короткий ответ будет таким: используйте друга, когда это действительно улучшает инкапсуляцию. Улучшение читаемости и удобства использования (операторы << и >> являются каноническим примером) также является хорошей причиной.

Что касается примеров улучшения инкапсуляции, то хорошими кандидатами являются классы, специально предназначенные для работы с внутренними компонентами других классов (тестовые классы приходят на ум).

Автор: Gorpik Размещён: 16.01.2009 08:33

2 плюса

9486 Репутация автора

Я использую только ключевое слово friend для проверки защищенных функций. Некоторые скажут, что вы не должны тестировать защищенную функциональность. Однако я нахожу этот очень полезный инструмент при добавлении новых функций.

Тем не менее, я не использую ключевое слово непосредственно в объявлениях класса, вместо этого я использую изящный шаблон-хак для достижения этой цели:

template<typename T>
class FriendIdentity {
public:
  typedef T me;
};

/**
 * A class to get access to protected stuff in unittests. Don't use
 * directly, use friendMe() instead.
 */
template<class ToFriend, typename ParentClass>
class Friender: public ParentClass
{
public:
  Friender() {}
  virtual ~Friender() {}
private:
// MSVC != GCC
#ifdef _MSC_VER
  friend ToFriend;
#else
  friend class FriendIdentity<ToFriend>::me;
#endif
};

/**
 * Gives access to protected variables/functions in unittests.
 * Usage: friendMe(this, someprotectedobject).someProtectedMethod();
 */
template
Friender & 
friendMe(Tester * me, ParentClass & instance)
{
    return (Friender &)(instance);
}

Это позволяет мне сделать следующее:

friendMe(this, someClassInstance).someProtectedFunction();

Работает на GCC и MSVC по крайней мере.

Автор: larsmoa Размещён: 07.09.2009 09:03

16 плюса

214664 Репутация автора

edit: Чтение faq немного дольше Мне нравится идея перегрузки оператора << >> и добавления в качестве друга этих классов, однако я не уверен, как это не нарушает инкапсуляцию

Как это нарушит инкапсуляцию?

Вы нарушаете инкапсуляцию, когда разрешаете неограниченный доступ к элементу данных. Рассмотрим следующие классы:

class c1 {
public:
  int x;
};

class c2 {
public:
  int foo();
private:
  int x;
};

class c3 {
  friend int foo();
private:
  int x;
};

c1это , очевидно , не инкапсулируется. Любой может прочитать и изменить xего. У нас нет способа обеспечить какой-либо контроль доступа.

c2очевидно инкапсулирован. Нет публичного доступа к x. Все, что вы можете сделать, это вызвать fooфункцию, которая выполняет значимую операцию над классом .

c3? Это менее инкапсулировано? Это разрешает неограниченный доступ к x? Разрешает ли доступ к неизвестным функциям?

Нет. Это позволяет точно одной функции получить доступ к закрытым членам класса. Так же, как и c2сделал. И точно так же c2, единственная функция, которая имеет доступ, это не «какая-то случайная, неизвестная функция», а «функция, указанная в определении класса». Также как c2мы можем увидеть, просто посмотрев определения классов, полный список тех, у кого есть доступ.

Так как именно это менее инкапсулировано? Такое же количество кода имеет доступ к закрытым членам класса. И каждый, у кого есть доступ, указан в определении класса.

friendне нарушает инкапсуляцию. Это заставляет некоторых программистов на Java чувствовать себя неловко, потому что когда они говорят «ООП», они на самом деле означают «Java». Когда они говорят «Инкапсуляция», они не означают «частные члены должны быть защищены от произвольного доступа», но «класс Java, где единственными функциями, которые могут получить доступ к закрытым членам, являются члены класса», хотя это полная чушь для несколько причин .

Во-первых, как уже показано, это слишком ограничивает. Нет причин, по которым методы друзей не должны делать то же самое.

Во- вторых, это не является ограничительным достаточно . Рассмотрим четвертый класс:

class c4 {
public:
  int getx();
  void setx(int x);
private:
  int x;
};

Это, согласно вышеупомянутому менталитету Java, прекрасно инкапсулировано. И все же, это позволяет абсолютно любому читать и изменять x . Как это вообще имеет смысл? (подсказка: это не так)

Итог: инкапсуляция - это возможность контролировать, какие функции могут получить доступ к закрытым членам. Речь идет не о том, где именно находятся определения этих функций.

Автор: jalf Размещён: 07.09.2009 09:24

3 плюса

740 Репутация автора

Другое использование: friend (+ виртуальное наследование) может быть использовано, чтобы избежать наследования от класса (иначе: «сделать класс недопустимым») => 1 , 2

Из 2 :

 class Fred;

 class FredBase {
 private:
   friend class Fred;
   FredBase() { }
 };

 class Fred : private virtual FredBase {
 public:
   ...
 }; 
Автор: Gian Paolo Ghilardi Размещён: 07.09.2009 09:38

4 плюса

1917 Репутация автора

Создатель C ++ говорит, что не нарушает принцип инкапсуляции, и я процитирую его:

«Друг» нарушает инкапсуляцию? Нет. «Друг» - это явный механизм предоставления доступа, как и членство. Вы не можете (в стандартной соответствующей программе) предоставить себе доступ к классу без изменения его источника.

Более чем понятно ...

Автор: garzanti Размещён: 11.02.2010 02:42

1 плюс

2153 Репутация автора

Friend functions and classes provide direct access to private and protected members of class to avoid breaking encapsulation in the general case. Most usage is with ostream: we would like to be able to type:

Point p;
cout << p;

However, this may require access to the private data of Point, so we define the overloaded operator

friend ostream& operator<<(ostream& output, const Point& p);

There are obvious encapsulation implications, however. First, now the friend class or function has full access to ALL members of the class, even ones that do not pertain to its needs. Second, the implementations of the class and the friend are now enmeshed to the point where an internal change in the class can break the friend.

If you view the friend as an extension of the class, then this is not an issue, logically speaking. But, in that case, why was it necessary to spearate out the friend in the first place.

To achieve the same thing that 'friends' purport to achieve, but without breaking encapsulation, one can do this:

class A
{
public:
    void need_your_data(B & myBuddy)
    {
        myBuddy.take_this_name(name_);
    }
private:
    string name_;
};

class B
{
public:
    void print_buddy_name(A & myBuddy)
    {
        myBuddy.need_your_data(*this);
    }
    void take_this_name(const string & name)
    {
        cout << name;
    }
}; 

Encapsulation is not broken, class B has no access to the internal implementation in A, yet the result is the same as if we had declared B a friend of A. The compiler will optimize away the function calls, so this will result in the same instructions as direct access.

I think using 'friend' is simply a shortcut with arguable benefit, but definite cost.

Автор: Lubo Antonov Размещён: 28.03.2012 02:08

2 плюса

5338 Репутация автора

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

Допустим, вы хотите сравнить два объекта, чтобы увидеть, равны ли они. Вы можете либо:

  • Используйте методы доступа, чтобы сделать сравнение (проверьте каждый ivar и определите равенство).
  • Или вы можете получить доступ ко всем участникам напрямую, сделав их публичными.

Проблема с первым вариантом заключается в том, что это может быть МНОГИЕ средства доступа, которые (немного) медленнее, чем прямой доступ к переменным, труднее читать и громоздки. Проблема второго подхода заключается в том, что вы полностью нарушаете инкапсуляцию.

Было бы неплохо, если бы мы могли определить внешнюю функцию, которая могла бы получить доступ к закрытым членам класса. Мы можем сделать это с friendключевым словом:

class Beer {
public:
    friend bool equal(Beer a, Beer b);
private:
    // ...
};

Метод в equal(Beer, Beer)настоящее время имеет прямой доступ к aи b«s частных пользователей (которые могут быть char *brand, float percentAlcoholи т.д. Это довольно надуманный пример, вы бы скорее обратиться friendк перегруженным == operator, но мы вернемся к этому.

Несколько вещей, на которые стоит обратить внимание:

  • A friendне является функцией-членом класса
  • Это обычная функция со специальным доступом к закрытым членам класса
  • Не заменяйте все аксессоры и мутаторы друзьями (вы можете также сделать все public!)
  • Дружба не взаимна
  • Дружба не переходная
  • Дружба не наследуется
  • Or, as the C++ FAQ explains: "Just because I grant you friendship access to me doesn't automatically grant your kids access to me, doesn't automatically grant your friends access to me, and doesn't automatically grant me access to you."

I only really use friends when it's much harder to do it the other way. As another example, many vector maths functions are often created as friends due to the interoperability of Mat2x2, Mat3x3, Mat4x4, Vec2, Vec3, Vec4, etc. And it's just so much easier to be friends, rather than have to use accessors everywhere. As pointed out, friend is often useful when applied to the << (really handy for debugging), >> and maybe the == operator, but can also be used for something like this:

class Birds {
public:
    friend Birds operator +(Birds, Birds);
private:
    int numberInFlock;
};


Birds operator +(Birds b1, Birds b2) {
    Birds temp;
    temp.numberInFlock = b1.numberInFlock + b2.numberInFlock;
    return temp;
}

As I say, I don't use friend very often at all, but every now and then it's just what you need. Hope this helps!

Автор: Ephemera Размещён: 29.12.2012 02:55

0 плюса

15356 Репутация автора

You may use friendship when different classes (not inheriting one from the other) are using private or protected members of the other class.

Typical use cases of friend functions are operations that are conducted between two different classes accessing private or protected members of both.

from http://www.cplusplus.com/doc/tutorial/inheritance/ .

You can see this example where non-member method accesses the private members of a class. This method has to be declared in this very class as a friend of the class.

// friend functions
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    Rectangle() {}
    Rectangle (int x, int y) : width(x), height(y) {}
    int area() {return width * height;}
    friend Rectangle duplicate (const Rectangle&);
};

Rectangle duplicate (const Rectangle& param)
{
  Rectangle res;
  res.width = param.width*2;
  res.height = param.height*2;
  return res;
}

int main () {
  Rectangle foo;
  Rectangle bar (2,3);
  foo = duplicate (bar);
  cout << foo.area() << '\n';
  return 0;
}
Автор: kiriloff Размещён: 06.02.2014 09:50

8 плюса

310 Репутация автора

Я нашел удобное место, чтобы использовать доступ друзей: Unittest личных функций.

Автор: VladimirS Размещён: 19.02.2015 07:34

1 плюс

95 Репутация автора

In C++ "friend" keyword is useful in Operator overloading and Making Bridge.

1.) Friend keyword in operator overloading :
Example for operator overloading is: Let say we have a class "Point" that has two float variable
"x"(for x-coordinate) and "y"(for y-coordinate). Now we have to overload "<<"(extraction operator) such that if we call "cout << pointobj" then it will print x and y coordinate (where pointobj is an object of class Point). To do this we have two option:

   1.Overload "operator <<()" function in "ostream" class.
   2.Overload "operator<<()" function in "Point" class.
Now First option is not good because if we need to overload again this operator for some different class then we have to again make change in "ostream" class.
That's why second is best option. Now compiler can call "operator <<()" function:

   1.Using ostream object cout.As: cout.operator<<(Pointobj) (form ostream class).
2.Call without an object.As: operator<<(cout, Pointobj) (from Point class).

Beacause we have implemented overloading in Point class. So to call this function without an object we have to add"friend" keyword because we can call a friend function without an object. Now function declaration will be As:
"friend ostream &operator<<(ostream &cout, Point &pointobj);"

2.) Friend keyword in making bridge :
Suppose we have to make a function in which we have to access private member of two or more classes ( generally termed as "bridge" ) . How to do this:
To access private member of a class it should be member of that class. Now to access private member of other class every class should declare that function as a friend function. For example : Suppose there are two class A and B. A function "funcBridge()" want to access private member of both classes. Then both class should declare "funcBridge()" as:
friend return_type funcBridge(A &a_obj, B & b_obj);

I think this would help to understand friend keyword.

Автор: Shiv Размещён: 25.03.2016 05:53

0 плюса

131 Репутация автора

Возможно, я что-то упустил из ответов выше, но другой важной концепцией инкапсуляции является скрытие реализации. Сокращение доступа к частным элементам данных (подробности реализации класса) позволяет значительно упростить модификацию кода позже. Если друг напрямую обращается к частным данным, любые изменения в полях данных реализации (личные данные) нарушают код доступа к этим данным. Использование методов доступа в основном устраняет это. Довольно важно, я думаю.

Автор: peterdcasey Размещён: 07.04.2016 08:01

0 плюса

5205 Репутация автора

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

Клуб Хаус

class ClubHouse {
public:
    friend class VIPMember; // VIP Members Have Full Access To Class
private:
    unsigned nonMembers_;
    unsigned paidMembers_;
    unsigned vipMembers;

    std::vector<Member> members_;
public:
    ClubHouse() : nonMembers_(0), paidMembers_(0), vipMembers(0) {}

    addMember( const Member& member ) { // ...code }   
    void updateMembership( unsigned memberID, Member::MembershipType type ) { // ...code }
    Amenity getAmenity( unsigned memberID ) { // ...code }

protected:
    void joinVIPEvent( unsigned memberID ) { // ...code }

}; // ClubHouse

Класс членов

class Member {
public:
    enum MemberShipType {
        NON_MEMBER_PAID_EVENT,   // Single Event Paid (At Door)
        PAID_MEMBERSHIP,         // Monthly - Yearly Subscription
        VIP_MEMBERSHIP,          // Highest Possible Membership
    }; // MemberShipType

protected:
    MemberShipType type_;
    unsigned id_;
    Amenity amenity_;
public:
    Member( unsigned id, MemberShipType type ) : id_(id), type_(type) {}
    virtual ~Member(){}
    unsigned getId() const { return id_; }
    MemberShipType getType() const { return type_; }
    virtual void getAmenityFromClubHouse() = 0       
};

class NonMember : public Member {
public:
   explicit NonMember( unsigned id ) : Member( id, MemberShipType::NON_MEMBER_PAID_EVENT ) {}   

   void getAmenityFromClubHouse() override {
       Amenity = ClubHouse::getAmenity( this->id_ );
    }
};

class PaidMember : public Member {
public:
    explicit PaidMember( unsigned id ) : Member( id, MemberShipType::PAID_MEMBERSHIP ) {}

    void getAmenityFromClubHouse() override {
       Amenity = ClubHouse::getAmenity( this->id_ );
    }
};

class VIPMember : public Member {
public:
    friend class ClubHouse;
public:
    explicit VIPMember( unsigned id ) : Member( id, MemberShipType::VIP_MEMBERSHIP ) {}

    void getAmenityFromClubHouse() override {
       Amenity = ClubHouse::getAmenity( this->id_ );
    }

    void attendVIPEvent() {
        ClubHouse::joinVIPEvent( this->id );
    }
};

Удобства

class Amenity{};

Если вы посмотрите на отношения этих классов здесь; ClubHouse предлагает различные виды членства и членства. Все члены являются производными от супер или базового класса, поскольку все они имеют общий идентификатор и перечислимый тип, и внешние классы могут получать доступ к своим идентификаторам и типам через функции доступа, которые находятся в базовом классе.

Однако благодаря такой иерархии членов и их производных классов и их отношений с классом ClubHouse единственным из производных классов, обладающих «особыми привилегиями», является класс VIPMember. Базовый класс и два других производных класса не могут получить доступ к методу joinVIPEvent () ClubHouse, однако у класса VIP-члена есть такая привилегия, как если бы он имел полный доступ к этому событию.

Таким образом, с VIPMember и ClubHouse это улица с двусторонним движением, где другие классы участников ограничены.

Автор: Francis Cugler Размещён: 12.02.2017 11:36

2 плюса

41 Репутация автора

As the reference for friend declaration says:

The friend declaration appears in a class body and grants a function or another class access to private and protected members of the class where the friend declaration appears.

So just as a reminder, there are technical errors in some of the answers which say that friend can only visit protected members.

Автор: lixunhuan Размещён: 18.08.2017 03:27
Вопросы из категории :
32x32