Когда необходимо использовать 'друга' в C++?

Сначала вам нужно получить тип mime, соответствующий файлу:

  • Открыть инструменты разработчика, а затем вкладку Сеть
  • Вернитесь на страницу и нажмите файл для загрузки
  • Вернитесь к панели сети и выберите первый запрос
  • Скопируйте тип mime справа от Content-Type из заголовка ответа:

  • Задайте предпочтение «browser.helperApps.neverAsk.saveToDisk» с вашим типом mime
  • Убедитесь, что папка загрузки "browser.download.dir" существует

Вот рабочий пример с Firefox:

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("browser.download.folderList", 2);
profile.setPreference("browser.download.dir", "C:\\Windows\\temp");
profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "application/vnd.ms-excel");
profile.setPreference("pdfjs.disabled", true);  // disable the built-in PDF viewer

WebDriver driver = new FirefoxDriver(profile);
driver.get("http://www.exinfm.com/free_spreadsheets.html");
driver.findElement(By.linkText("Capital Budgeting Analysis")).click();

342
задан 8 revs, 4 users 52% 15 June 2017 в 08:54
поделиться

22 ответа

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

СУЩЕСТВУЮТ альтернативы другу спецификатор, но часто они являются громоздкими (классы бетона cpp-уровня / определения типов маскированные) или не надежными (комментарии или соглашения имени функции).

На ответ;

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

можно взять этот простой пример далее путем рассмотрения более сложного класса, такого как Окно. Довольно вероятно, Окно будет иметь многих функцией/элементами данных, которая не должна быть публично доступна, но необходима связанному классу, такому как 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 );
};
325
ответ дан Andrew Grant 23 November 2019 в 00:33
поделиться

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

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;
}

становится легче скрыть вещи, что нисходящий поток не должен видеть этот путь.

-1
ответ дан shash 23 November 2019 в 00:33
поделиться

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

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

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

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

-1
ответ дан Mark Cidade 23 November 2019 в 00:33
поделиться

При реализации древовидных алгоритмов для класса код платформы профессор дал нам, имел древовидный класс как друга класса узла.

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

0
ответ дан Ryan Fox 23 November 2019 в 00:33
поделиться

Один определенный экземпляр, где я использую friend, при создании Singleton классы. friend ключевое слово позволяет мне создать функцию средства доступа, которая более кратка, чем всегда наличие "GetInstance ()" метод на классе.

/////////////////////////
// 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;
}
1
ответ дан Matt Dillard 23 November 2019 в 00:33
поделиться

Для делания TDD много раз я использовал 'друга' ключевое слово в C++.
друг может знать все обо мне?

нет, ее единственное один путь дружба: '(

1
ответ дан roo 23 November 2019 в 00:33
поделиться

Древовидным примером является довольно хороший пример: реализация объекта в некоторых различный класс, не имея отношений наследования.

, Возможно, Вам мог также быть нужен он, чтобы защитить конструктора и вынудить людей использовать Вашего "друга" фабрика.

... Хорошо, Хорошо откровенно можно жить без него.

1
ответ дан fulmicoton 23 November 2019 в 00:33
поделиться

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

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

2
ответ дан 23 November 2019 в 00:33
поделиться

Другая общая версия примера Andrew, страшное двустишие кода

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);
}

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

10
ответ дан maccullt 23 November 2019 в 00:33
поделиться

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

         Game
        /    \
 TwoPlayer  SinglePlayer

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

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

3
ответ дан Ray 23 November 2019 в 00:33
поделиться

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

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

4
ответ дан Gorpik 23 November 2019 в 00:33
поделиться

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

5
ответ дан ΦXocę 웃 Пepeúpa ツ 23 November 2019 в 00:33
поделиться

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

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

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

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

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

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

8
ответ дан csmba 23 November 2019 в 00:33
поделиться

Для делания TDD много раз, я использовал 'друга' ключевое слово в C++.

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

<час>

Обновленный: Я нашел этот ценный ответ о "друге" ключевым словом от сайт Bjarne Stroustrup .

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

3
ответ дан Jacob 23 November 2019 в 00:33
поделиться

Канонический пример должен перегрузить operator< <. другое общее использование должно предоставить доступ класса помощника или администратора к Вашим внутренностям.

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

  • Ваши друзья не являются друзьями Вашего ребенка.
  • друзья Вашего ребенка не являются Вашими друзьями.
  • Только друзья могут коснуться Ваших половых органов.
27
ответ дан Mark Harrison 23 November 2019 в 00:33
поделиться

@roo: Инкапсуляция не повреждается здесь, потому что сам класс диктует, кто может получить доступ к его членам парламента, не занимающим официального поста. Инкапсуляция была бы только повреждена, если бы это могло бы быть вызвано снаружи класса, например, если Ваш operator << объявил бы “I'm, друг класса foo.”

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

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

41
ответ дан Community 23 November 2019 в 00:33
поделиться

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 бросает свой этот указатель, чтобы быть в состоянии получить доступ к полям данных производного класса с помощью указателей элемента данных.

92
ответ дан Community 23 November 2019 в 00:33
поделиться

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

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

154
ответ дан einpoklum - reinstate Monica 23 November 2019 в 00:33
поделиться

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

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

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: <code>friendMe(this, someprotectedobject).someProtectedMethod();</code>
 */
template<typename Tester, typename ParentClass>
Friender<Tester, ParentClass> & 
friendMe(Tester * me, ParentClass & instance)
{
    return (Friender<Tester, ParentClass> &)(instance);
}

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

friendMe(this, someClassInstance).someProtectedFunction();

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

2
ответ дан 23 November 2019 в 00:33
поделиться

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

Из 2 :

 class Fred;

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

 class Fred : private virtual FredBase {
 public:
   ...
 }; 
3
ответ дан 23 November 2019 в 00:33
поделиться

У любого из них разные цели:

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

  • return true или false : специализация кодов ошибок. Любой желающий может прочитать и изменить в нем 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 . Как это вообще имеет смысл? (подсказка: это не так)

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

16
ответ дан 23 November 2019 в 00:33
поделиться

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

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

Более чем ясно ...

4
ответ дан 23 November 2019 в 00:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: