Saya tidak pernah benar-benar mengerti mengapa C ++ membutuhkan file header terpisah dengan fungsi yang sama seperti pada file .cpp. Itu membuat pembuatan kelas dan pemfaktoran ulang mereka sangat sulit, dan itu menambahkan file yang tidak perlu ke proyek. Dan kemudian ada masalah dengan harus menyertakan file header, tetapi harus secara eksplisit memeriksa apakah sudah disertakan.
C ++ diratifikasi pada tahun 1998, lalu mengapa didesain seperti ini? Apa keuntungan memiliki file header terpisah?
Pertanyaan lanjutan:
Bagaimana kompilator menemukan file .cpp dengan kode di dalamnya, jika yang saya sertakan hanyalah file .h? Apakah ini berasumsi bahwa file .cpp memiliki nama yang sama dengan file .h, atau apakah itu benar-benar melihat semua file di pohon direktori?
sumber
Jawaban:
Anda sepertinya bertanya tentang memisahkan definisi dari deklarasi, meskipun ada kegunaan lain untuk file header.
Jawabannya adalah C ++ tidak "membutuhkan" ini. Jika Anda menandai semuanya sebaris (yang tetap otomatis untuk fungsi anggota yang ditentukan dalam definisi kelas), maka tidak perlu pemisahan. Anda bisa menentukan semuanya di file header.
Alasan Anda mungkin ingin memisahkan adalah:
Jika pertanyaan Anda yang lebih umum adalah, "mengapa C ++ tidak identik dengan Java?", Maka saya harus bertanya, "mengapa Anda menulis C ++ daripada Java?" ;-p
Lebih serius lagi, alasannya adalah bahwa compiler C ++ tidak bisa begitu saja menjangkau unit terjemahan lain dan mencari cara menggunakan simbol-simbolnya, seperti yang bisa dan dilakukan javac. File header diperlukan untuk mendeklarasikan kepada compiler apa yang diharapkan tersedia pada waktu penautan.
Begitu
#include
juga dengan substitusi tekstual lurus. Jika Anda mendefinisikan semuanya di file header, preprocessor akhirnya membuat salinan dan paste yang sangat besar dari setiap file sumber dalam proyek Anda, dan memasukkannya ke dalam kompilator. Fakta bahwa standar C ++ diratifikasi pada tahun 1998 tidak ada hubungannya dengan hal ini, itu fakta bahwa lingkungan kompilasi untuk C ++ sangat dekat dengan lingkungan C.Mengubah komentar saya untuk menjawab pertanyaan tindak lanjut Anda:
Tidak, setidaknya pada saat itu mengkompilasi kode yang menggunakan file header. Fungsi-fungsi yang Anda tautkan bahkan belum perlu ditulis, apalagi kompilator mengetahui
.cpp
file apa yang akan digunakan. Semua yang perlu diketahui kode pemanggil pada waktu kompilasi diekspresikan dalam deklarasi fungsi. Pada waktu tautan Anda akan memberikan daftar.o
file, atau pustaka statis atau dinamis, dan header yang berlaku adalah janji bahwa definisi fungsi akan ada di sana di suatu tempat.sumber
C ++ melakukannya seperti itu karena C melakukannya seperti itu, jadi pertanyaan sebenarnya adalah mengapa C melakukannya seperti itu? Wikipedia berbicara sedikit tentang ini.
sumber
Beberapa orang menganggap file header sebagai keuntungan:
Pada akhirnya, sistem header adalah artefak dari tahun 70-an ketika C dirancang. Saat itu, komputer memiliki sedikit memori, dan menyimpan seluruh modul dalam memori bukanlah pilihan. Kompiler harus mulai membaca file dari atas, dan kemudian melanjutkan secara linier melalui kode sumber. Mekanisme header memungkinkan ini. Kompilator tidak harus mempertimbangkan unit terjemahan lain, ia hanya perlu membaca kode dari atas ke bawah.
Dan C ++ mempertahankan sistem ini untuk kompatibilitas ke belakang.
Hari ini, itu tidak masuk akal. Itu tidak efisien, rawan kesalahan dan terlalu rumit. Ada cara yang jauh lebih baik untuk memisahkan antarmuka dan implementasi, jika itu adalah tujuan.
Namun, salah satu proposal untuk C ++ 0x adalah untuk menambahkan sistem modul yang tepat, yang memungkinkan kode untuk dikompilasi mirip dengan .NET atau Java, menjadi modul yang lebih besar, semuanya dalam sekali jalan dan tanpa header. Proposal ini tidak lolos di C ++ 0x, tapi saya yakin itu masih dalam kategori "kami akan senang melakukannya nanti". Mungkin di TR2 atau serupa.
sumber
Untuk pemahaman saya (terbatas - saya bukan C developer biasanya), ini berakar pada C. Ingat bahwa C tidak tahu apa itu kelas atau namespace, itu hanya satu program yang panjang. Selain itu, fungsi harus dideklarasikan sebelum Anda menggunakannya.
Misalnya, berikut ini akan memberikan kesalahan kompiler:
void SomeFunction() { SomeOtherFunction(); } void SomeOtherFunction() { printf("What?"); }
Kesalahannya adalah "SomeOtherFunction tidak dideklarasikan" karena Anda memanggilnya sebelum deklarasinya. Salah satu cara untuk memperbaikinya adalah dengan memindahkan SomeOtherFunction di atas SomeFunction. Pendekatan lain adalah mendeklarasikan tanda tangan fungsi terlebih dahulu:
void SomeOtherFunction(); void SomeFunction() { SomeOtherFunction(); } void SomeOtherFunction() { printf("What?"); }
Hal ini memungkinkan kompilator mengetahui: Lihat di suatu tempat di kode, ada fungsi bernama SomeOtherFunction yang mengembalikan void dan tidak mengambil parameter apa pun. Jadi jika Anda encouter kode yang mencoba memanggil SomeOtherFunction, jangan panik dan cari saja.
Sekarang, bayangkan Anda memiliki SomeFunction dan SomeOtherFunction dalam dua file .c yang berbeda. Anda kemudian harus #memasukkan "SomeOther.c" di Some.c. Sekarang, tambahkan beberapa fungsi "pribadi" ke SomeOther.c. Karena C tidak mengetahui fungsi privat, fungsi itu akan tersedia di Some.c juga.
Di sinilah File .h masuk: Mereka menentukan semua fungsi (dan variabel) yang ingin Anda 'Ekspor' dari file .c yang dapat diakses di file .c lainnya. Dengan begitu, Anda mendapatkan sesuatu seperti cakupan Publik / Pribadi. Selain itu, Anda dapat memberikan file .h ini kepada orang lain tanpa harus membagikan kode sumber Anda - file .h juga dapat digunakan pada file .lib yang dikompilasi.
Jadi, alasan utamanya adalah untuk kenyamanan, untuk perlindungan kode sumber dan untuk memiliki sedikit pemisahan antara bagian-bagian aplikasi Anda.
Itu C sekalipun. C ++ memperkenalkan Classes dan pengubah privat / publik, jadi meskipun Anda masih bisa menanyakan apakah mereka diperlukan, C ++ AFAIK masih memerlukan deklarasi fungsi sebelum menggunakannya. Juga, banyak Pengembang C ++ adalah atau merupakan pengembang C juga dan mengambil alih konsep dan kebiasaan mereka ke C ++ - mengapa mengubah apa yang tidak rusak?
sumber
Keuntungan pertama: Jika Anda tidak memiliki file header, Anda harus menyertakan file sumber di file sumber lain. Ini akan menyebabkan file yang termasuk dikompilasi lagi ketika file yang disertakan berubah.
Keuntungan kedua: Ini memungkinkan berbagi antarmuka tanpa berbagi kode antara unit yang berbeda (pengembang, tim, perusahaan yang berbeda, dll ..)
sumber
Kebutuhan akan file header diakibatkan oleh keterbatasan yang dimiliki compiler untuk mengetahui informasi jenis untuk fungsi dan atau variabel dalam modul lain. Program atau pustaka yang dikompilasi tidak menyertakan informasi jenis yang diperlukan oleh kompilator untuk mengikat objek apa pun yang ditentukan dalam unit kompilasi lain.
Untuk mengimbangi batasan ini, C dan C ++ memungkinkan deklarasi dan deklarasi ini dapat dimasukkan ke dalam modul yang menggunakannya dengan bantuan arahan #include preprocessor.
Bahasa seperti Java atau C # di sisi lain menyertakan informasi yang diperlukan untuk mengikat dalam keluaran kompiler (file kelas atau perakitan). Oleh karena itu, tidak perlu lagi mempertahankan deklarasi mandiri untuk disertakan oleh klien modul.
Alasan informasi binding tidak disertakan dalam output compiler adalah sederhana: tidak diperlukan pada waktu proses (semua jenis pemeriksaan terjadi pada waktu kompilasi). Itu hanya akan membuang-buang ruang. Ingatlah bahwa C / C ++ berasal dari waktu di mana ukuran executable atau pustaka cukup penting.
sumber
C ++ dirancang untuk menambahkan fitur bahasa pemrograman modern ke infrastruktur C, tanpa perlu mengubah apa pun tentang C yang tidak secara khusus tentang bahasa itu sendiri.
Ya, pada titik ini (10 tahun setelah standar C ++ pertama dan 20 tahun setelah standar tersebut mulai berkembang secara serius dalam penggunaan) mudah untuk ditanyakan mengapa tidak memiliki sistem modul yang tepat. Jelas sekali bahasa baru apa pun yang sedang dirancang saat ini tidak akan berfungsi seperti C ++. Tapi itu bukan inti dari C ++.
Inti dari C ++ adalah untuk menjadi evolusioner, kelanjutan yang mulus dari praktik yang ada, hanya menambahkan kemampuan baru tanpa (terlalu sering) merusak hal-hal yang berfungsi secara memadai untuk komunitas penggunanya.
Ini berarti itu membuat beberapa hal menjadi lebih sulit (terutama bagi orang yang memulai proyek baru), dan beberapa hal lebih mudah (terutama bagi mereka yang memelihara kode yang ada) daripada yang dilakukan bahasa lain.
Jadi daripada mengharapkan C ++ berubah menjadi C # (yang tidak ada gunanya karena kita sudah memiliki C #), mengapa tidak memilih alat yang tepat untuk pekerjaan itu? Saya sendiri, saya berusaha untuk menulis potongan signifikan dari fungsionalitas baru dalam bahasa modern (saya kebetulan menggunakan C #), dan saya memiliki sejumlah besar C ++ yang saya simpan di C ++ karena tidak akan ada nilai nyata dalam menulis ulang itu semua. Mereka berintegrasi dengan sangat baik, jadi sebagian besar tidak menimbulkan rasa sakit.
sumber
Nah, C ++ telah diratifikasi pada tahun 1998, tetapi telah digunakan lebih lama dari itu, dan ratifikasi tersebut terutama menetapkan penggunaan saat ini daripada memaksakan struktur. Dan karena C ++ didasarkan pada C, dan C memiliki file header, C ++ juga memilikinya.
Alasan utama untuk file header adalah untuk mengaktifkan kompilasi file terpisah, dan meminimalkan ketergantungan.
Katakanlah saya memiliki foo.cpp, dan saya ingin menggunakan kode dari file bar.h / bar.cpp.
Saya bisa # menyertakan "bar.h" di foo.cpp, dan kemudian memprogram dan mengkompilasi foo.cpp bahkan jika bar.cpp tidak ada. File header bertindak sebagai janji kepada compiler bahwa class / functions di bar.h akan ada pada saat run-time, dan memiliki semua yang perlu diketahui.
Tentu saja, jika fungsi di bar.h tidak memiliki badan ketika saya mencoba menautkan program saya, maka itu tidak akan menautkan dan saya akan mendapatkan kesalahan.
Efek sampingnya adalah Anda dapat memberikan file header kepada pengguna tanpa mengungkapkan kode sumber Anda.
Hal lainnya adalah jika Anda mengubah implementasi kode Anda di file * .cpp, tetapi tidak mengubah header sama sekali, Anda hanya perlu mengompilasi file * .cpp daripada semua yang menggunakannya. Tentu saja, jika Anda menerapkan banyak implementasi ke file header, maka ini menjadi kurang berguna.
sumber
Itu tidak membutuhkan file header terpisah dengan fungsi yang sama seperti di main. Ini hanya membutuhkannya jika Anda mengembangkan aplikasi menggunakan beberapa file kode dan jika Anda menggunakan fungsi yang tidak dideklarasikan sebelumnya.
Ini benar-benar masalah ruang lingkup.
sumber
Sebenarnya file header menjadi sangat berguna saat memeriksa program untuk pertama kalinya, memeriksa file header (hanya menggunakan editor teks) memberi Anda gambaran umum tentang arsitektur program, tidak seperti bahasa lain di mana Anda harus menggunakan alat canggih untuk melihat kelas dan fungsi anggota mereka.
sumber
Saya pikir alasan sebenarnya (historis) di balik file header membuat lebih mudah bagi pengembang kompiler ... tetapi kemudian, file header memang memberikan keuntungan.
Periksa posting sebelumnya ini untuk diskusi lebih lanjut ...
sumber
Nah, Anda dapat mengembangkan C ++ dengan sempurna tanpa file header. Faktanya, beberapa pustaka yang secara intensif menggunakan templat tidak menggunakan paradigma file header / kode (lihat peningkatan). Tetapi Di C / C ++ Anda tidak dapat menggunakan sesuatu yang tidak dideklarasikan. Salah satu cara praktis untuk mengatasinya adalah dengan menggunakan file header. Plus, Anda mendapatkan keuntungan dari berbagi antarmuka tanpa kode / implementasi berbagi. Dan saya pikir itu tidak dibayangkan oleh pembuat C: Saat Anda menggunakan file header bersama, Anda harus menggunakan yang terkenal:
#ifndef MY_HEADER_SWEET_GUARDIAN #define MY_HEADER_SWEET_GUARDIAN // [...] // my header // [...] #endif // MY_HEADER_SWEET_GUARDIAN
itu sebenarnya bukan fitur bahasa tetapi cara praktis untuk menangani banyak penyertaan.
Jadi, saya pikir ketika C dibuat, masalah dengan deklarasi maju diremehkan dan sekarang ketika menggunakan bahasa tingkat tinggi seperti C ++ kita harus berurusan dengan hal-hal semacam ini.
Beban lain bagi kami pengguna C ++ yang malang ...
sumber
Jika Anda ingin kompilator menemukan simbol yang didefinisikan dalam file lain secara otomatis, Anda perlu memaksa pemrogram untuk meletakkan file-file tersebut di lokasi yang telah ditentukan (seperti struktur paket Java menentukan struktur folder proyek). Saya lebih suka file header. Anda juga memerlukan sumber pustaka yang Anda gunakan atau beberapa cara seragam untuk meletakkan informasi yang dibutuhkan oleh kompilator dalam binari.
sumber