C ++ другові чи ні


19

У цьому семестрі в коледжі я маю об’єктно-орієнтоване програмування з курсом c ++, і ми вивчали функції друзів.

Я інстинктивно не люблю їх за їхню здатність обходити безпеку, яку забезпечує інкапсуляція та приховування даних, я прочитав кілька статей в Інтернеті, і деякі люди думали, що це гарна ідея з деякими законними цілями.

Що б сказав експерт ООС про вивіски друзів на C ++? Я повинен просто скуйовджуватись над цим чи повинен дізнатися більше про нього?


@all: Чудові відповіді та зауваження. Це такий чудовий спосіб вчитися, я не можу дізнатися про друзів у таких підручниках.
nikhil

Відповіді:


13

Не завжди зручно робити всі функції, пов'язані з членами класу C ++ цього класу. Наприклад, уявіть реалізацію векторної алгебри зі скалярним множенням. Ми хочемо написати:

 double a;
 Vector v, w;
 w = v * a;

Це можна зробити за допомогою функції-члена:

public class Vector {
 ...
 Vector operator*(double a);
}

Але ми також хотіли б написати:

w = a * v

Для цього потрібна безкоштовна функція:

 Vector operator*(double a, Vector v)

friendКлючове слово було додано в C ++ , щоб підтримати це використання. Безкоштовна функція є частиною реалізації класу Vector і повинна бути оголошена в одному заголовку та реалізована в тому самому вихідному файлі.

Аналогічно ми можемо використовувати friendдля спрощення реалізації щільно зв'язаних класів, як колекція та ітератор. Знову я б оголосив обидва класи в одному заголовку і реалізував їх у тому самому вихідному файлі.


3
"Для цього потрібна вільна функція". Ні, це не робить: inline Vector operator*(double a, Vector v) { return v*a; }. Канонічне рішення насправді.
MSalters

1
@MSalters: Добре. Я вибрав поганий приклад. Я думаю, що ваша вбудована функція є вільною функцією за визначенням, але декларація про друзів не потрібна.
кевін клайн

4
@MSalters: Це справедливо, лише якщо * є комутативним відношенням до a і v (x). Якщо векторні компоненти є загальними (не обов'язково скалярними), ви повинні дотримуватися порядку операндів
Еміліо Гаравалія

Це досить теоретично. Мабуть, єдиним поширеним випадком, inline Vector operator*(double a, Vector v) { return -v*a; }що не стосується комунікацій, був би той, який все ще не потребує дружби.
MSalters

16

Дружні функції нічим не відрізняються від функцій-членів з точки зору інкапсуляції. Однак вони можуть запропонувати і інші переваги - наприклад, більш загальні, особливо там, де йдеться про шаблони. Крім того, деякі оператори можуть бути визначені лише як безкоштовні функції, тому, якщо ви хочете, щоб вони мали доступ до членів, ви повинні friend.

Краще виконати friendодну функцію, ніж бути змушеним робити щось, про що ви не хочете бути загальнодоступним. Це означає, що весь світ може використовувати його, а не лише одну функцію.


+1 для функцій Friend не відрізняється від функцій-членів з точки зору інкапсуляції. Однак це стосується лише функцій державних членів.
TheFogger

1
@TheFogger: Можливо, ви також friendможете функцію, яка також є "приватною", наприклад, оголошеною лише в одному ТУ.
DeadMG

5

Якщо ви захоплені тим, чим займаєтесь, ви б дізналися все про C ++. Дізнайтеся, для чого вони використовуються, як їх використовувати, а потім - і тільки тоді - вирішіть не використовувати їх. Як мінімум, ви будете готові до читання чужого коду, який використовує цю грань C ++.


5

" Що б сказав експерт ООС ... " В основному це залежить від того, наскільки він досвідчений на C ++, що - за його власними специфікаціями - не є (і не хоче бути) мовою для пуриста.

OOP Zealots не використовують C ++ (вони віддають перевагу Smalltalk і люблять Java).

У функціональному програмуванні зеленики не використовують C ++ (вони віддають перевагу LISP та його наступникам)

Більшість експертів OOP не люблять функцію друзів просто тому, що вони хочуть, щоб частина OOP C ++ поводилася як Smalltalk. Але C ++ не є Smalltalk, і вони навіть не можуть зрозуміти, що друг не порушує інкапсуляцію , з тієї простої причини, що функція не може бути другом вашого класу, якщо ваш клас цього не хоче .

І з точки зору "функціональності", між a.fn(b)і fn(a,b)немає різниці (де fnдруг): залучені сторони однакові. Просто один синтаксис може бути більш підходящим, ніж інший: якщо fn є комутативним відносно aі b, fn(a,b)ймовірно , є більш підходящим тоді a.fn(b)(де погляд має "особливу роль", що, власне, він не робить.)


1
"Зустрічі OOP", яким подобається Java, не зрозуміли OOP. Геттери? Сетери? Немає простого синтаксису для закриття? Якщо перефразовувати Алана Кей, це не те, як він уявляв OOP.
Конрад Рудольф

@Konrad: ревнощі не обмежені. Завжди є завзяття більше завзяття, ніж даний ревець.
Еміліо Гаравалья

Треба сказати, що я підтримав те, що мені дуже сподобався останній абзац. Має багато сенсу.
julealgon


2

C ++ FAQ є лаконічним:

Користуйтеся членом, коли можете, а другом, коли потрібно.

Найчастіші запитання та відповіді представляють один із найбільш корисних способів мислення про дружбу:

Багато людей думають про те, що друга функціонує як щось поза класом. Натомість спробуйте думати про функцію друга як частину публічного інтерфейсу класу. Функція друга в декларації класу не порушує інкапсуляцію більше, ніж функція публічного члена порушує інкапсуляцію: обидва мають точно однакові повноваження щодо доступу до непублічних частин класу.

Мабуть, найпоширенішим використанням функцій друга є перевантаження << для вводу / виводу.


0

Дружні функції найкраще використовувати для визначених користувачем визначень оператора. Вони корисні в інших ситуаціях, але якщо ви часто вказуєте дружні класи, то, можливо, ви перебуваєте в об’їзді дизайну (просто хороша самоперевірка, яку слід використовувати під час написання коду).

Будьте уважні до заяви про безпеку в оригінальному запитанні. Модифікатори доступу існують, щоб запобігти написанню поганого коду випадково, як і компілятор певним чином. Модифікатори доступу обмежують інтерфейс і служать для спілкування, які функції важливі для використання класу (загальнодоступні та захищені), а які - створені як частина, щоб зробити клас гарнішим для обслуговуючого персоналу (приватного). Модифікатори не є безпекою, оскільки існує багато способів отримати приватні дані. Наприклад, знайдіть вказівник на клас та його розмір та вирушайте на риболовлю.


-2

Функції друзів C ++ тісно пов'язані з наступними функціоналами:

  1. вільні функції
  2. статичні функції
  3. функції друга

Це означає, що вони не мають цього покажчика і тому знаходяться поза класом / об'єктом. З іншого боку, вони часто приймають параметри, завдяки яким вони знову належать до класу. Ось приклад, який уточнює посилання:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

Єдина відмінність статичних функцій від функцій друга полягає в тому, що функція друга може використовувати кілька класів.

Для використання механізму друзів у c ++ потрібні програмісти, які мають близько 10-15 років досвіду роботи зі способом програмування c ++, і, таким чином, спочатку вам слід уникати цього. Це розширена функція.


7
А ти виводив 10-15 років як?
DeadMG

10-15 років настає з того часу, коли вперше стають фактично необхідними.
tp1

3
Отже, ви довільно склали число.
DeadMG

3
-1: "Вам слід цього уникати". Кожна функція C ++ була створена для вирішення проблеми. Коли ця проблема виникає, скористайтеся відповідною функцією.
кевін клайн

Дякую за -1 У цьому коментарі була причина. Здогадайтесь, це просто складна концепція того, що не всі функції підходять для початківців.
tp1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.