Mengapa kita perlu menempatkan anggota pribadi di header?

62

Variabel pribadi adalah cara untuk menyembunyikan kerumitan dan detail implementasi kepada pengguna kelas. Ini adalah fitur yang agak bagus. Tapi saya tidak mengerti mengapa di c ++ kita harus meletakkannya di header sebuah kelas. Saya melihat dua kelemahan yang mengganggu ini:

  • Itu mengacaukan header dari pengguna
  • Ini memaksa kompilasi ulang semua perpustakaan klien setiap kali internal diubah

Apakah ada alasan konseptual di balik persyaratan ini? Apakah hanya untuk memudahkan pekerjaan di luar kompiler?

Simon Bergot
sumber
Anda dapat mendeklarasikan struct kosong di header tetapi kemudian Anda hanya dapat menggunakan pointer ke struct tersebut ketika Anda menggunakannya (dan Anda tidak dapat mengalokasikannya)
ratchet freak
3
@ scratchetfreak: Tidak, kosong ( struct foo{};) tidak diperbolehkan, tetapi meneruskan deklarasi ( struct foo;) adalah.
MSalters
@Malters itulah yang saya maksud
ratchet freak
1
Izinkan saya menambahkan kerugian: * Menulis header fungsi pribadi dalam file .h adalah buang-buang waktu. (lupa kelas teman sejenak)
Jonny

Jawaban:

68

Itu karena kompiler C ++ harus mengetahui ukuran sebenarnya dari kelas untuk mengalokasikan jumlah memori yang tepat pada instantiasi. Dan ukurannya mencakup semua anggota, juga yang pribadi.

Salah satu cara untuk menghindari hal ini adalah dengan menggunakan idiom Pimpl , yang dijelaskan oleh Herb Sutter dalam seri # 24 dan # 28 dari Guru of the Week .

Memperbarui

Memang, ini (atau lebih umum, perbedaan / #includes file sumber file dan s) adalah rintangan utama dalam C ++, diwarisi dari C. Kembali pada hari-hari C ++ C dibuat, belum ada pengalaman dengan pengembangan perangkat lunak skala besar, di mana ini mulai menimbulkan masalah nyata. Pelajaran yang dipetik sejak saat itu diperhatikan oleh perancang bahasa yang lebih baru, tetapi C ++ terikat oleh persyaratan kompatibilitas ke belakang, membuatnya sangat sulit untuk mengatasi masalah mendasar dalam bahasa tersebut.

Péter Török
sumber
Bukankah informasi semacam ini hanya ada di perpustakaan kelas? Apakah ini digunakan untuk menghubungkan?
Simon Bergot
@Simon, apa yang Anda maksud dengan "perpustakaan kelas"?
Péter Török
Maksud saya koleksi file objek yang berisi definisi dan metode kelas
Simon Bergot
7
Ketika C ++ dibuat, AT&T / Bell Labs (perusahaan Stroustrups pada saat itu) tentu memiliki pengalaman dengan pengembangan C skala besar. Perangkat lunak peralihan telepon 5ESS mereka pada waktu itu mungkin merupakan program C tunggal terbesar di dunia. Gagasan awal tentang OO sudah terlihat dalam basis kode itu, dan Cfront meniru teknik-teknik itu. Namun, anggapan privatelebih modern.
MSalters
1
Di C, Anda cukup menempatkan pengalokasi di fungsi perpustakaan; klien tidak akan dapat mengalokasikan struktur seperti itu sama sekali. Ini sedikit meningkatkan overhead, tetapi membuat migrasi kode lintas versi menjadi sepele sehingga sering bermanfaat. Namun, itu cenderung mengarah ke gaya kode yang sangat berbeda dari yang terlihat dengan C ++.
Donal Fellows
15

Definisi kelas harus cukup bagi kompiler untuk menghasilkan tata letak yang identik dalam memori di mana pun Anda telah menggunakan objek kelas. Misalnya, diberikan sesuatu seperti:

class X { 
    int a;
public:
    int b;
};

Kompiler biasanya memiliki aoffset 0, dan boffset 4. Jika kompilator melihat ini hanya sebagai:

class X { 
public:
    int b;
};

Itu akan "berpikir" yang bharus diimbangi 0 bukannya diimbangi 4. Ketika kode menggunakan definisi yang ditugaskan b, kode menggunakan definisi pertama akan melihat abisa dimodifikasi, dan sebaliknya.

Cara biasa untuk meminimalkan efek membuat perubahan pada bagian pribadi kelas biasanya disebut idiom pimpl (yang saya yakin Google dapat memberikan banyak informasi).

Jerry Coffin
sumber
1
Saya bertanya tentang keputusan desain. Tentu saja Anda harus meletakkan deklarasi anggota pribadi di suatu tempat agar bahasa dapat berfungsi. Tapi mengapa harus di header dan bukan di tempat yang lebih pribadi?
Simon Bergot
7
@Simon: Header adalah semua yang dilihat oleh kompiler untuk memberi tahu seperti apa bentuk class / struct. Telah ada diskusi tentang menambahkan sesuatu seperti modul ke C ++, yang akan menyembunyikan data semacam itu sedikit lebih banyak, tetapi sejauh ini belum disetujui (meskipun belum sepenuhnya dibatalkan).
Jerry Coffin
3
Namun, aturan sepele adalah mengalokasikan anggota pribadi ".cpp-defined" seperti itu untuk yang terakhir. Itu berarti offset anggota publik dan "normal" tidak akan bergantung pada mereka. IMO alasan sebenarnya adalah bahwa Anda tidak dapat mewarisi dari kelas seperti itu, karena bagian turunannya harus mengikuti bahkan anggota pribadi tersebut.
MSalters
3

Kemungkinan besar ada beberapa alasan. Sementara anggota pribadi tidak dapat diakses oleh sebagian besar kelas lain, mereka masih dapat diakses oleh kelas teman. Jadi setidaknya dalam hal ini mereka mungkin diperlukan di header, sehingga kelas teman dapat melihat keberadaannya.

Kompilasi file dependen mungkin tergantung pada struktur include Anda. Termasuk file .h dalam file .cpp sebagai ganti header lain dalam beberapa kasus dapat mencegah rantai panjang kompilasi ulang.

thorsten müller
sumber