NB Ini bukan pertanyaan tentang bagaimana menggunakan fungsi sebaris atau bagaimana mereka bekerja, lebih banyak mengapa mereka dilakukan sebagaimana adanya.
Deklarasi fungsi anggota kelas tidak perlu mendefinisikan fungsi inline
, ini hanya implementasi sebenarnya dari fungsi tersebut. Misalnya, di file header:
struct foo{
void bar(); // no need to define this as inline
}
Jadi mengapa implementasi inline dari fungsi kelas harus berada di file header? Mengapa saya tidak bisa meletakkan fungsi sebaris di .cpp
file? Jika saya mencoba meletakkan definisi sebaris di .cpp
file, saya akan mendapatkan kesalahan di sepanjang baris:
error LNK2019: unresolved external symbol
"public: void __thiscall foo::bar(void)"
(?bar@foo@@QAEXXZ) referenced in function _main
1>C:\Users\Me\Documents\Visual Studio 2012\Projects\inline\Debug\inline.exe
: fatal error LNK1120: 1 unresolved externals
inline
muncul pada definisi tetapi bukan deklarasi sebelumnya vs sebaliknya . Jika demikian, ini dapat membantu: stackoverflow.com/questions/4924912/…Jawaban:
Definisi suatu
inline
fungsi tidak harus dalam file header tetapi, karena aturan satu definisi ( ODR ) untuk fungsi sebaris, definisi yang identik untuk fungsi tersebut harus ada di setiap unit terjemahan yang menggunakannya.Cara termudah untuk melakukannya adalah dengan meletakkan definisi di file header.
Jika Anda ingin meletakkan definisi suatu fungsi dalam satu file sumber maka Anda tidak boleh mendeklarasikannya
inline
. Sebuah fungsi tidak dideklarasikaninline
tidak berarti bahwa compiler tidak dapat menyebariskan fungsi tersebut.Apakah Anda harus mendeklarasikan suatu fungsi
inline
atau tidak biasanya merupakan pilihan yang harus Anda buat berdasarkan versi mana dari aturan definisi satu yang paling masuk akal untuk Anda ikuti; menambahkaninline
dan kemudian dibatasi oleh batasan berikutnya tidak masuk akal.sumber
+1
dari saya!Ada dua cara untuk melihatnya:
Fungsi sebaris didefinisikan di tajuk karena, untuk menyebariskan pemanggilan fungsi, penyusun harus dapat melihat isi fungsi. Agar kompiler naif dapat melakukan itu, badan fungsi harus berada dalam unit terjemahan yang sama dengan pemanggilan. (Kompiler modern dapat mengoptimalkan di seluruh unit terjemahan, sehingga pemanggilan fungsi mungkin sebaris meskipun definisi fungsi berada dalam unit terjemahan terpisah, tetapi pengoptimalan ini mahal, tidak selalu diaktifkan, dan tidak selalu didukung oleh penyusun)
fungsi yang didefinisikan di header harus ditandai
inline
karena jika tidak, setiap unit terjemahan yang menyertakan header akan berisi definisi fungsi, dan linker akan mengeluh tentang beberapa definisi (pelanggaran terhadap One Definition Rule). Katainline
kunci menekan ini, memungkinkan beberapa unit terjemahan berisi definisi (identik).Kedua penjelasan tersebut benar-benar bermuara pada fakta bahwa
inline
kata kunci tidak persis melakukan apa yang Anda harapkan.Kompiler C ++ bebas untuk menerapkan pengoptimalan sebaris (mengganti panggilan fungsi dengan isi fungsi yang dipanggil, menghemat overhead panggilan) kapan saja, selama tidak mengubah perilaku program yang dapat diamati.
Kata
inline
kunci mempermudah penyusun untuk menerapkan pengoptimalan ini, dengan memungkinkan definisi fungsi terlihat di beberapa unit terjemahan, tetapi menggunakan kata kunci tidak berarti penyusun harus menyebariskan fungsi, dan tidak menggunakan kata kunci tidak. melarang kompilator untuk menyebariskan fungsi.sumber
Ini adalah batas kompiler C ++. Jika Anda meletakkan fungsi di tajuk, semua file cpp yang dapat dijadikan sebaris dapat melihat "sumber" fungsi Anda dan penyebarisan dapat dilakukan oleh kompilator. Selain itu, penyebarisan harus dilakukan oleh linker (setiap file cpp dikompilasi dalam file obj secara terpisah). Masalahnya adalah akan jauh lebih sulit untuk melakukannya di linker. Masalah serupa terjadi dengan kelas / fungsi "template". Mereka perlu dibuat instance-nya oleh compiler, karena linker akan mengalami masalah dalam membuat instance (membuat versi khusus). Beberapa kompilator / penaut yang lebih baru dapat melakukan kompilasi / penautan "dua lintasan" di mana kompilator melakukan lintasan pertama, kemudian penaut melakukan tugasnya dan memanggil kompilator untuk menyelesaikan hal-hal yang belum terselesaikan (inline / templates ...)
sumber
Alasannya adalah bahwa kompilator harus benar-benar melihat definisi tersebut agar dapat meletakkannya di tempat panggilan.
Ingatlah bahwa C dan C ++ menggunakan model kompilasi yang sangat sederhana, di mana kompiler selalu hanya melihat satu unit terjemahan dalam satu waktu. (Ini gagal untuk ekspor, yang merupakan alasan utama hanya satu vendor yang benar-benar menerapkannya.)
sumber
Kata
inline
kunci c ++ menyesatkan, itu tidak berarti "sebariskan fungsi ini". Jika suatu fungsi didefinisikan sebagai sebaris, itu berarti bahwa itu dapat didefinisikan beberapa kali selama semua definisi sama. Ini sangat legal untuk fungsi yang ditandaiinline
sebagai fungsi nyata yang dipanggil alih-alih memasukkan kode pada titik di mana ia dipanggil.Mendefinisikan fungsi dalam file header diperlukan untuk template, karena misalnya kelas templated sebenarnya bukan kelas, ini adalah template untuk kelas yang dapat Anda buat beberapa variasi. Agar kompilator dapat, misalnya membuat
Foo<int>::bar()
fungsi saat Anda menggunakan template Foo untuk membuat kelas Foo , definisi sebenarnya dariFoo<T>::bar()
harus terlihat.sumber
inline
(juga tidak mendeklarasikannyainline
menjamin bahwa itu tidak akan sebaris).Saya tahu ini adalah utas lama tetapi saya pikir saya harus menyebutkan
extern
kata kunci itu. Saya baru-baru ini mengalami masalah ini dan menyelesaikannya sebagai berikutHelper.h
Helper.cpp
sumber
Karena kompilator perlu melihatnya untuk menyebariskannya . Dan file header adalah "komponen" yang biasanya disertakan dalam unit terjemahan lain.
sumber
Fungsi Inline
Dalam C ++ makro tidak lain adalah fungsi sebaris. SO sekarang makro berada di bawah kendali compiler.
Kode fungsi Inline diganti di tempat pemanggilan, sehingga mengurangi overhead fungsi pemanggilan.
Dalam beberapa kasus, fungsi Inlining tidak dapat berfungsi, seperti
Jika variabel statis digunakan di dalam fungsi sebaris.
Jika fungsinya rumit.
Jika panggilan fungsi rekursif
Jika alamat fungsi diambil secara implisit atau eksplisit
Fungsi yang didefinisikan di luar kelas seperti di bawah ini mungkin menjadi sebaris
Fungsi yang didefinisikan di dalam kelas juga menjadi sebaris
Di sini, fungsi getSpeed dan setSpeed akan menjadi sebaris
sumber