C ++ ke teman atau tidak ke teman

19

Saya memiliki pemrograman berorientasi objek dengan kursus c ++ semester ini di kampus dan kami belajar tentang fungsi teman.

Saya secara naluriah tidak menyukai mereka karena kemampuan mereka untuk melewati keamanan yang disediakan Enkapsulasi dan Penyembunyian Data, saya membaca beberapa artikel di internet dan beberapa orang berpikir itu adalah ide yang bagus dengan beberapa penggunaan yang sah.

Apa yang akan dikatakan pakar OOP tentang fungsi teman di C ++? Haruskah saya membaca sepintas lalu atau saya harus belajar lebih banyak tentang itu?

nikhil
sumber
@all: Jawaban dan komentar yang luar biasa, Ini adalah cara yang bagus untuk belajar, tidak mungkin saya telah belajar tentang teman dalam perincian seperti itu di buku teks.
nikhil

Jawaban:

13

Tidak selalu nyaman untuk membuat semua fungsi yang terkait dengan anggota kelas C ++ dari kelas itu. Sebagai contoh, bayangkan implementasi aljabar vektor dengan perkalian skalar. Kami ingin menulis:

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

Kita dapat melakukan ini dengan fungsi anggota:

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

Tetapi kami juga ingin menulis:

w = a * v

Ini membutuhkan fungsi gratis:

 Vector operator*(double a, Vector v)

Kata friendkunci ditambahkan ke C ++ untuk mendukung penggunaan ini. Fungsi bebas adalah bagian dari implementasi kelas Vector, dan harus dinyatakan dalam header yang sama dan diimplementasikan dalam file sumber yang sama.

Demikian pula kita dapat menggunakan frienduntuk menyederhanakan implementasi kelas yang digabungkan secara ketat, seperti koleksi dan iterator. Sekali lagi, saya akan mendeklarasikan kedua kelas di header yang sama, dan mengimplementasikannya dalam file sumber yang sama.

kevin cline
sumber
3
"Ini membutuhkan fungsi bebas". Tidak, itu tidak: inline Vector operator*(double a, Vector v) { return v*a; }. Solusi kanonik sebenarnya.
MSalters
1
@ MSalters: Poin bagus. Saya mengambil contoh yang buruk. Saya pikir fungsi inline Anda adalah fungsi bebas menurut definisi, tetapi tidak ada pernyataan teman yang diperlukan.
kevin cline
4
@MSalters: Itu hanya valid jika * adalah komutatif terhadap a dan v (x). Jika komponen vektornya generik (belum tentu skalar) Anda harus menjaga urutan operan
Emilio Garavaglia
Itu cukup teoretis. Mungkin satu-satunya kasus non-komutatif yang umum terjadi inline Vector operator*(double a, Vector v) { return -v*a; }dan itu masih tidak membutuhkan persahabatan.
MSalters
16

Fungsi teman tidak berbeda dengan fungsi anggota dalam hal enkapsulasi. Mereka dapat, bagaimanapun, menawarkan keuntungan lain - seperti menjadi lebih umum, terutama di mana template yang bersangkutan. Selain itu, beberapa operator hanya dapat ditentukan sebagai fungsi bebas, jadi jika Anda ingin mereka memiliki akses anggota, Anda harus friend.

Lebih baik friendfungsi tunggal daripada dipaksa untuk membuat sesuatu yang Anda tidak ingin publik. Itu berarti seluruh dunia dapat menggunakannya - bukan hanya satu fungsi.

DeadMG
sumber
+1 untuk fungsi Teman tidak berbeda dengan fungsi anggota dalam hal enkapsulasi. Ini hanya berlaku untuk fungsi anggota publik.
TheFogger
1
@TheFogger: Bisa dibilang, Anda juga bisa friendfungsi yang juga "pribadi", seperti hanya dinyatakan dalam TU tunggal.
DeadMG
5

Jika Anda bersemangat tentang apa yang Anda lakukan, Anda akan belajar segalanya tentang C ++. Pelajari untuk apa mereka digunakan, bagaimana menggunakannya, dan kemudian - dan hanya kemudian - memutuskan untuk tidak menggunakannya. Paling tidak, Anda akan siap ketika membaca kode orang lain yang menggunakan aspek C ++ ini.

JK
sumber
5

" Apa yang akan dikatakan ahli OOP ... " Sebagian besar tergantung pada seberapa ahli dia dalam C ++, bahwa -dengan spesifikasinya sendiri - bukan (dan tidak ingin) bahasa untuk purist.

OOP Zelot tidak menggunakan C ++ (mereka lebih suka Smalltalk, dan seperti Java).

Zelots pemrograman fungsional tidak menggunakan C ++ (mereka lebih suka LISP, dan penggantinya)

Sebagian besar pakar OOP tidak menyukai fungsi teman hanya karena mereka ingin bagian OOP C ++ berperilaku seperti Smalltalk. Tetapi C ++ bukan Smalltalk, dan mereka bahkan tidak dapat mengerti bahwa teman tidak merusak enkapsulasi , karena alasan yang sangat sederhana bahwa suatu fungsi tidak dapat menjadi teman kelas Anda tanpa kelas Anda menginginkannya .

Dan dari sudut pandang "fungsionalitas", antara a.fn(b)dan fn(a,b)tidak ada perbedaan (di mana fnada teman): pihak yang terlibat adalah sama. Sederhananya, satu sintaks mungkin lebih cocok daripada yang lain: jika fn bersifat komutatif adan b, fn(a,b)mungkin lebih cocok kemudian a.fn(b)(di mana penampilan memiliki "peran khusus" yang, pada kenyataannya, tidak.)

Emilio Garavaglia
sumber
1
"OOP fanatik" yang menyukai Java belum mengerti OOP. Getters? Setter? Tidak ada sintaksis sederhana untuk penutupan? Mengutip Alan Kay, ini bukan bagaimana dia membayangkan OOP.
Konrad Rudolph
@ Konrad: zealot adalah atur tanpa batas. Selalu ada seorang fanatik lebih fanatik daripada fanatik yang diberikan.
Emilio Garavaglia
Saya harus mengatakan saya terangkat karena saya sangat menyukai paragraf terakhir itu. Masuk akal.
julealgon
5

Apakah "teman" melanggar enkapsulasi?

Tidak. "Teman" adalah mekanisme eksplisit untuk memberikan akses, seperti halnya keanggotaan. Anda tidak dapat (dalam program penyesuaian standar) memberikan diri Anda akses ke kelas tanpa memodifikasi sumbernya.

fredoverflow
sumber
2

The C ++ FAQ adalah ringkas:

Gunakan anggota saat Anda bisa, dan teman ketika Anda harus.

FAQ menyajikan salah satu cara berpikir yang lebih berguna tentang persahabatan:

Banyak orang menganggap fungsi teman sebagai sesuatu di luar kelas. Alih-alih, coba pikirkan fungsi teman sebagai bagian dari antarmuka publik kelas. Fungsi teman dalam deklarasi kelas tidak melanggar enkapsulasi seperti halnya fungsi anggota publik melanggar enkapsulasi: keduanya memiliki wewenang yang persis sama sehubungan dengan mengakses bagian-bagian non-publik kelas.

Mungkin penggunaan fungsi teman yang paling umum adalah kelebihan << untuk I / O.

Gnawme
sumber
0

Fungsi teman paling baik digunakan untuk definisi operator yang ditentukan pengguna. Mereka berguna dalam situasi lain, tetapi jika Anda mendapati diri Anda sering menentukan kelas teman maka Anda mungkin akan mengambil jalan memutar (hanya pemeriksaan diri yang baik untuk digunakan saat menulis kode).

Berhati-hatilah dengan pernyataan "keamanan" dalam pertanyaan awal. Akses pengubah ada untuk mencegah Anda menulis kode buruk secara tidak sengaja, seperti halnya kompiler. Pengubah akses membatasi antarmuka, dan berfungsi untuk mengkomunikasikan fungsi apa yang penting untuk menggunakan kelas (publik dan terlindungi), dan mana yang dibuat sebagai bagian dari membuat kelas lebih cantik untuk pengelola (pribadi). Pengubah bukan merupakan keamanan karena ada banyak cara untuk mendapatkan data pribadi. Misalnya, dapatkan pointer ke kelas dan ukurannya, dan pergi memancing.

segera
sumber
-2

Fungsi teman C ++ terkait erat dengan fungsi berikut:

  1. fungsi gratis
  2. fungsi statis
  3. fungsi teman

Ini berarti bahwa mereka tidak memiliki pointer-ini dan dengan demikian berada di luar kelas / objek. Di sisi lain, mereka sering mengambil parameter yang membuat mereka kembali menjadi bagian dari kelas. Berikut beberapa contoh yang menjelaskan tautan:

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 */ }

Satu-satunya perbedaan antara fungsi statis dan fungsi teman adalah bahwa fungsi teman dapat menggunakan beberapa kelas.

Menggunakan mekanisme pertemanan di c ++ membutuhkan programmer yang memiliki pengalaman sekitar 10-15 tahun dengan cara pemrograman c ++, dan karenanya pada awalnya Anda harus menghindarinya. Ini fitur canggih.

tp1
sumber
7
Dan Anda berasal 10-15 tahun bagaimana?
DeadMG
10-15 tahun datang dari waktu ketika pertama kali menjadi benar-benar diperlukan.
tp1
3
Jadi Anda sewenang-wenang membuat nomor, lalu.
DeadMG
3
-1: "Anda harus menghindarinya." Setiap fitur C ++ dibuat untuk memecahkan masalah. Ketika masalah itu muncul, gunakan fitur yang sesuai.
kevin cline
Terima kasih atas -1. Ada alasan untuk komentar itu. Kira itu hanya konsep yang sulit bahwa tidak semua fitur cocok untuk pemula.
tp1