Catatan: Jawaban diberikan dalam urutan tertentu , tetapi karena banyak pengguna mengurutkan jawaban berdasarkan suara, daripada waktu mereka diberikan, inilah indeks jawaban sesuai urutan yang paling masuk akal:
- Sintaks Umum operator kelebihan muatan di C ++
- Tiga Aturan Dasar Operator Overloading di C ++
- Keputusan antara Anggota dan Non-anggota
- Operator umum kelebihan beban
- Operator Penugasan
- Operator Input dan Output
- Operator panggilan fungsi
- Operator pembanding
- Operator Aritmatika
- Array Berlangganan
- Operator untuk Jenis Pointer-like
- Operator Konversi
- Overloading baru dan hapus
(Catatan: Ini dimaksudkan sebagai entri untuk FAQ C ++ Stack Overflow . Jika Anda ingin mengkritik gagasan memberikan FAQ dalam formulir ini, maka posting pada meta yang memulai semua ini akan menjadi tempat untuk melakukan itu. Jawaban untuk pertanyaan itu dipantau di chatroom C ++ , di mana ide FAQ dimulai sejak awal, jadi jawaban Anda sangat mungkin untuk dibaca oleh mereka yang mengemukakan ide itu.)
Jawaban:
Operator umum kelebihan beban
Sebagian besar pekerjaan di operator kelebihan muatan adalah kode boiler-plate. Itu tidak mengherankan, karena operator hanyalah gula sintaksis, pekerjaan mereka yang sebenarnya dapat dilakukan dengan (dan sering diteruskan ke) fungsi sederhana. Tetapi penting bahwa Anda mendapatkan kode pelat ketel ini dengan benar. Jika Anda gagal, kode operator Anda tidak dapat dikompilasi atau kode pengguna Anda tidak akan dikompilasi atau kode pengguna Anda akan berperilaku mengejutkan.
Operator Penugasan
Ada banyak yang bisa dikatakan tentang tugas. Namun, sebagian besar sudah dikatakan di FAQ Copy-and-Swap terkenal GMan , jadi saya akan melewatkan sebagian besar di sini, hanya daftar operator penugasan yang sempurna untuk referensi:
Operator Bitshift (digunakan untuk Stream I / O)
Operator bitshift
<<
dan>>
, meskipun masih digunakan dalam interfacing perangkat keras untuk fungsi manipulasi bit yang mereka warisi dari C, telah menjadi lebih lazim sebagai operator input dan output stream yang kelebihan beban di sebagian besar aplikasi. Untuk panduan kelebihan muatan sebagai operator manipulasi bit, lihat bagian di bawah ini tentang Operator Aritmatika Biner. Untuk menerapkan format kustom dan logika parsing saat objek Anda digunakan dengan iostreams, lanjutkan.Operator stream, di antara operator yang paling sering kelebihan beban, adalah operator infiks biner dimana sintaksnya tidak menetapkan batasan apakah mereka harus anggota atau bukan. Karena mereka mengubah argumen kiri mereka (mereka mengubah keadaan aliran), mereka harus, menurut aturan praktis, diimplementasikan sebagai anggota tipe operan kiri mereka. Namun, operan kiri mereka adalah stream dari library standar, dan sementara sebagian besar output stream dan operator input didefinisikan oleh library standar memang didefinisikan sebagai anggota kelas stream, ketika Anda mengimplementasikan operasi output dan input untuk tipe Anda sendiri, Anda tidak dapat mengubah jenis aliran perpustakaan standar. Itu sebabnya Anda perlu mengimplementasikan operator ini untuk tipe Anda sendiri sebagai fungsi non-anggota. Bentuk kanonik keduanya adalah sebagai berikut:
Saat menerapkan
operator>>
, mengatur keadaan aliran secara manual hanya diperlukan ketika pembacaan itu sendiri berhasil, tetapi hasilnya tidak seperti yang diharapkan.Operator panggilan fungsi
Operator fungsi panggilan, yang digunakan untuk membuat objek fungsi, juga dikenal sebagai functors, harus didefinisikan sebagai fungsi anggota , sehingga selalu memiliki
this
argumen implisit fungsi anggota. Selain ini, dapat kelebihan beban untuk mengambil sejumlah argumen tambahan, termasuk nol.Berikut ini contoh sintaksnya:
Pemakaian:
Di seluruh pustaka standar C ++, objek fungsi selalu disalin. Objek fungsi Anda sendiri karenanya harus murah untuk disalin. Jika objek fungsi benar-benar perlu menggunakan data yang mahal untuk disalin, lebih baik menyimpan data itu di tempat lain dan meminta objek fungsi merujuknya.
Operator pembanding
Operator pembanding infiks biner harus, sesuai dengan aturan praktis, diimplementasikan sebagai fungsi non-anggota 1 . Negasi awalan unary
!
harus (sesuai dengan aturan yang sama) diimplementasikan sebagai fungsi anggota. (tapi biasanya itu bukan ide yang baik untuk membebani itu.)Algoritme pustaka standar (mis.
std::sort()
) Dan tipe (misstd::map
) akan selalu hanya berharapoperator<
untuk hadir. Namun, pengguna tipe Anda akan mengharapkan semua operator lain juga hadir , jadi jika Anda mendefinisikanoperator<
, pastikan untuk mengikuti aturan mendasar ketiga dari operator yang berlebihan dan juga mendefinisikan semua operator perbandingan boolean lainnya. Cara kanonik untuk mengimplementasikannya adalah ini:Yang penting untuk dicatat di sini adalah bahwa hanya dua dari operator ini yang benar-benar melakukan apa saja, yang lain hanya meneruskan argumen mereka ke salah satu dari dua ini untuk melakukan pekerjaan yang sebenarnya.
Sintaks untuk overloading operator boolean biner yang tersisa (
||
,&&
) mengikuti aturan operator perbandingan. Namun, sangat tidak mungkin bahwa Anda akan menemukan use case yang masuk akal untuk 2 ini .1 Seperti semua aturan praktis lainnya, terkadang mungkin ada alasan untuk melanggarnya. Jika demikian, jangan lupa bahwa operan kiri dari operator perbandingan biner, yang untuk fungsi anggota akan
*this
, perluconst
juga demikian. Jadi operator perbandingan yang diimplementasikan sebagai fungsi anggota harus memiliki tanda tangan ini:(Catat
const
di bagian akhir.)2 Perlu dicatat bahwa versi built-in
||
dan&&
menggunakan cara pintas semantik. Sementara yang ditentukan pengguna (karena mereka adalah sintaksis gula untuk panggilan metode) tidak menggunakan semantik pintasan. Pengguna akan mengharapkan operator ini untuk memiliki semantik pintasan, dan kode mereka mungkin bergantung padanya, Oleh karena itu sangat disarankan untuk tidak mendefinisikannya.Operator Aritmatika
Operator aritmatika unary
Operator kenaikan dan penurunan unary datang dalam rasa awalan dan postfix. Untuk membedakan satu dari yang lain, varian postfix mengambil argumen int dummy tambahan. Jika Anda menambah atau mengurangi secara berlebihan, pastikan untuk selalu menerapkan versi awalan dan postfix. Berikut ini adalah implementasi kenaikan kanonik, penurunan mengikuti aturan yang sama:
Perhatikan bahwa varian postfix diimplementasikan dalam bentuk awalan. Perhatikan juga bahwa postfix melakukan salinan tambahan. 2
Overload minus dan plus unary tidak terlalu umum dan mungkin sebaiknya dihindari. Jika diperlukan, mereka mungkin harus kelebihan beban sebagai fungsi anggota.
2 Juga perhatikan bahwa varian postfix bekerja lebih banyak dan karenanya kurang efisien untuk digunakan daripada varian prefix. Ini adalah alasan yang bagus untuk secara umum lebih memilih kenaikan awalan daripada kenaikan postfix. Sementara kompiler biasanya dapat mengoptimalkan pekerjaan tambahan dari penambahan postfix untuk tipe bawaan, mereka mungkin tidak dapat melakukan hal yang sama untuk tipe yang ditentukan pengguna (yang bisa menjadi sesuatu yang tampak seperti daftar iterator). Setelah Anda terbiasa melakukannya
i++
, menjadi sangat sulit untuk diingat untuk melakukan++i
sebaliknya ketikai
bukan dari tipe built-in (ditambah Anda harus mengubah kode ketika mengubah jenis), jadi lebih baik untuk membuat kebiasaan untuk selalu menggunakan peningkatan awalan, kecuali postfix secara eksplisit diperlukan.Operator aritmatika biner
Untuk operator aritmatika biner, jangan lupa mematuhi aturan dasar operator ketiga yang berlebihan: Jika Anda memberikan
+
, juga memberikan+=
, jika Anda memberikan-
, jangan menghilangkan-=
, dll. Andrew Koenig dikatakan sebagai orang pertama yang mengamati penugasan majemuk. operator dapat digunakan sebagai pangkalan untuk rekanan non-majemuk mereka. Artinya, operator+
diimplementasikan dalam hal+=
,-
diimplementasikan dalam hal-=
dll.Menurut aturan praktis kami,
+
dan teman-temannya harus bukan anggota, sedangkan rekan tugas penugasan mereka (+=
dll.), Mengubah argumen kiri mereka, harus menjadi anggota. Berikut adalah contoh teladan untuk+=
dan+
; operator aritmatika biner lainnya harus diimplementasikan dengan cara yang sama:operator+=
mengembalikan hasilnya per referensi, sementaraoperator+
mengembalikan salinan hasilnya. Tentu saja, mengembalikan referensi biasanya lebih efisien daripada mengembalikan salinan, tetapi dalam kasusoperator+
, tidak ada jalan lain untuk menyalin. Ketika Anda menulisa + b
, Anda mengharapkan hasilnya menjadi nilai baru, itulah sebabnya mengapaoperator+
harus mengembalikan nilai baru. 3 Juga perhatikan bahwaoperator+
mengambil operan kirinya dengan menyalin daripada dengan referensi const. Alasan untuk ini sama dengan alasan memberi untukoperator=
mengambil argumennya per salinan.Operator manipulasi bit
~
&
|
^
<<
>>
harus diimplementasikan dengan cara yang sama seperti operator aritmatika. Namun, (kecuali untuk overloading<<
dan>>
untuk output dan input) ada beberapa kasus penggunaan yang wajar untuk overloading ini.3 Sekali lagi, pelajaran yang bisa diambil dari ini adalah bahwa
a += b
, secara umum, lebih efisien daripadaa + b
dan harus disukai jika memungkinkan.Array Berlangganan
Operator subscript array adalah operator biner yang harus diimplementasikan sebagai anggota kelas. Ini digunakan untuk tipe seperti wadah yang memungkinkan akses ke elemen data mereka dengan kunci. Bentuk kanonik dari menyediakan ini adalah ini:
Kecuali Anda tidak ingin pengguna kelas Anda dapat mengubah elemen data yang dikembalikan oleh
operator[]
(dalam hal ini Anda dapat menghilangkan varian non-const), Anda harus selalu menyediakan kedua varian operator.Jika value_type diketahui merujuk ke tipe bawaan, varian const operator sebaiknya mengembalikan salinan daripada referensi const:
Operator untuk Jenis Pointer-like
Untuk menentukan iterator atau smart pointer Anda sendiri, Anda harus membebani operator dereference awalan unary
*
dan operator akses anggota penunjuk infix biner->
:Perhatikan bahwa ini juga hampir selalu membutuhkan versi const dan non-const. Untuk
->
operator, jikavalue_type
dariclass
(ataustruct
atauunion
) tipe, yang lainoperator->()
disebut secara rekursif, sampaioperator->()
mengembalikan nilai tipe non-kelas.Operator alamat-unary tidak boleh kelebihan beban.
Untuk
operator->*()
melihat pertanyaan ini . Ini jarang digunakan dan karena itu jarang kelebihan beban. Bahkan, iterator sekalipun tidak membebani terlalu banyak.Lanjutkan ke Operator Konversi
sumber
operator->()
sebenarnya sangat aneh. Ini tidak diharuskan untuk mengembalikanvalue_type*
- pada kenyataannya, itu dapat mengembalikan tipe kelas yang lain, asalkan tipe kelas itu memilikioperator->()
, yang kemudian akan dipanggil selanjutnya. Panggilan rekursif inioperator->()
berlangsung hinggavalue_type*
jenis kembali terjadi. Kegilaan! :)*
dalam hal*=
tetapi itu akan menjadi canggung karena salah satu operasi pertama*=
akan membuat objek baru, hasil dari perhitungan. Kemudian, setelah for-ijk loop, kita akan menukar objek sementara ini dengan*this
. yaitu. 1. copy, 2.operator *, 3.swapT* const
pengembalianconst T&
pada dereferencing, yang tidak demikian. Atau dengan kata lain: pointer const tidak menyiratkan pointee const. Bahkan, itu tidak sepele untuk meniruT const *
- yang merupakan alasan untuk seluruhconst_iterator
hal di perpustakaan standar. Kesimpulan: tanda tangan harusreference_type operator*() const; pointer_type operator->() const
L <= R
juga bisa dinyatakan sebagai!(R < L)
bukan!(L > R)
. Mungkin menyimpan lapisan tambahan inlining dalam ekspresi yang sulit dioptimalkan (dan itu juga bagaimana Boost.Operators mengimplementasikannya).Tiga Aturan Dasar Operator Overloading di C ++
Ketika datang ke operator overloading di C ++, ada tiga aturan dasar yang harus Anda ikuti . Seperti halnya semua aturan semacam itu, memang ada pengecualian. Kadang-kadang orang menyimpang dari mereka dan hasilnya bukan kode yang buruk, tetapi penyimpangan positif seperti itu sangat sedikit. Paling tidak, 99 dari 100 penyimpangan yang saya lihat tidak bisa dibenarkan. Namun, mungkin hanya 999 dari 1000. Jadi sebaiknya Anda tetap pada aturan berikut.
Kapan pun makna operator tidak jelas dan tidak perlu dipersoalkan, itu tidak boleh kelebihan beban. Sebagai gantinya, berikan fungsi dengan nama yang dipilih dengan baik.
Pada dasarnya, aturan pertama dan terpenting untuk operator yang kelebihan beban, pada intinya, mengatakan: Jangan lakukan itu . Itu mungkin tampak aneh, karena ada banyak yang harus diketahui tentang kelebihan operator dan begitu banyak artikel, bab buku, dan teks-teks lain berurusan dengan semua ini. Tetapi terlepas dari bukti yang tampak jelas ini, hanya ada beberapa kasus yang mengejutkan di mana operator kelebihan beban sesuai. Alasannya adalah bahwa sebenarnya sulit untuk memahami semantik di balik aplikasi operator kecuali jika penggunaan operator dalam domain aplikasi diketahui dan tidak perlu dipersoalkan. Bertentangan dengan kepercayaan populer, ini hampir tidak pernah terjadi.
Selalu berpegang pada semantik yang terkenal dari operator.
C ++ tidak memberikan batasan pada semantik dari operator yang kelebihan beban. Kompiler Anda akan dengan senang hati menerima kode yang mengimplementasikan
+
operatorbineruntuk mengurangi dari operan yang tepat. Namun, pengguna dari operator tersebut tidak akan pernah menduga ekspresia + b
untuk mengurangia
darib
. Tentu saja, ini mengandaikan bahwa semantik operator dalam domain aplikasi tidak perlu dipersoalkan lagi.Selalu sediakan semua dari serangkaian operasi terkait.
Operator terkait satu sama lain dan dengan operasi lain. Jika tipe Anda mendukung
a + b
, pengguna juga diharapkan dapat menelepona += b
. Jika mendukung peningkatan awalan++a
, mereka akana++
bekerja dengan baik. Jika mereka dapat memeriksa apakaha < b
, mereka pasti akan berharap juga untuk dapat memeriksa apakaha > b
. Jika mereka dapat menyalin-membangun tipe Anda, mereka mengharapkan tugas juga berfungsi.Lanjutkan ke Keputusan antara Anggota dan Non-anggota .
sumber
boost::spirit
lol.+
penggabungan string adalah pelanggaran, tetapi sekarang sudah menjadi praksis yang sudah mapan, sehingga tampak alami. Meskipun saya ingat kelas string home-brew yang saya lihat di tahun 90-an yang menggunakan biner&
untuk tujuan ini (merujuk pada BASIC untuk praksis yang dibuat). Tapi, ya, memasukkannya ke std lib pada dasarnya mengatur ini di atas batu. Hal yang sama berlaku untuk penyalahgunaan<<
dan>>
untuk IO, BTW. Mengapa pergeseran kiri menjadi operasi output yang jelas? Karena kita semua mempelajarinya ketika kita melihat "Halo, dunia!" aplikasi. Dan tanpa alasan lain.operator==
adalah bahwa itu harus menjadi hubungan ekivalensi (TKI, Anda tidak boleh menggunakan NaN non pensinyalan). Ada banyak hubungan kesetaraan yang berguna pada wadah. Apa arti kesetaraan? "a
sama denganb
" berarti itua
danb
memiliki nilai matematika yang sama. Konsep nilai matematika dari (non-NaN)float
jelas, tetapi nilai matematika dari suatu wadah dapat memiliki banyak definisi yang berguna (tipe rekursif). Definisi kesetaraan terkuat adalah "mereka adalah objek yang sama", dan itu tidak berguna.Sintaks Umum operator kelebihan muatan di C ++
Anda tidak dapat mengubah arti operator untuk tipe bawaan di C ++, operator hanya bisa kelebihan beban untuk tipe yang ditentukan pengguna 1 . Artinya, setidaknya satu operan harus dari tipe yang ditentukan pengguna. Seperti halnya fungsi kelebihan beban lainnya, operator dapat kelebihan beban untuk satu set parameter tertentu hanya sekali.
Tidak semua operator dapat kelebihan muatan di C ++. Di antara operator yang tidak dapat kelebihan beban adalah:
.
::
sizeof
typeid
.*
dan satu-satunya operator ternary di C ++,?:
Di antara operator yang dapat kelebihan beban di C ++ adalah ini:
+
-
*
/
%
dan+=
-=
*=
/=
%=
(semua infiks biner);+
-
(awalan unary);++
--
(awalan dan postfix unary)&
|
^
<<
>>
dan&=
|=
^=
<<=
>>=
(semua infix biner);~
(awalan unary)==
!=
<
>
<=
>=
||
&&
(semua infiks biner);!
(awalan unary)new
new[]
delete
delete[]
=
[]
->
->*
,
(semua infix biner);*
&
(semua awalan unary)()
(panggilan fungsi, infix n-ary)Namun, fakta bahwa Anda dapat membebani semua ini tidak berarti Anda harus melakukannya. Lihat aturan dasar overloading operator.
Dalam C ++, operator kelebihan beban dalam bentuk fungsi dengan nama khusus . Seperti fungsi lainnya, operator kelebihan beban umumnya dapat diimplementasikan baik sebagai fungsi anggota dari jenis operan kiri mereka atau sebagai fungsi non-anggota . Apakah Anda bebas memilih atau terikat untuk menggunakan salah satu tergantung pada beberapa kriteria. 2 Operator unary
@
3 , diterapkan pada objek x, dipanggil sebagaioperator@(x)
atau sebagaix.operator@()
. Operator infiks biner@
, diterapkan pada objekx
dany
, disebut sebagaioperator@(x,y)
atau sebagaix.operator@(y)
. 4Operator yang diimplementasikan sebagai fungsi non-anggota kadang-kadang berteman dengan tipe operan mereka.
1 Istilah "yang ditentukan pengguna" mungkin sedikit menyesatkan. C ++ membuat perbedaan antara tipe bawaan dan tipe yang ditentukan pengguna. Untuk mantan milik misalnya int, char, dan double; yang terakhir termasuk semua tipe struct, class, union, dan enum, termasuk yang dari library standar, meskipun mereka tidak, dengan demikian, didefinisikan oleh pengguna.
2 Ini dibahas di bagian selanjutnya dari FAQ ini.
3 Ini
@
bukan operator yang valid di C ++ yang mengapa saya menggunakannya sebagai pengganti.4 Satu-satunya operator ternary di C ++ tidak dapat kelebihan beban dan satu-satunya operator n-ary harus selalu diimplementasikan sebagai fungsi anggota.
Lanjutkan ke Tiga Aturan Dasar tentang Kelebihan Operator di C ++ .
sumber
~
adalah awalan unary, bukan infix biner..*
hilang dari daftar operator yang tidak kelebihan muatan.:)
operator+()
sebagai fungsi anggota, tetapi memberinya tanda tangan dari fungsi bebas. Lihat di sini .Keputusan antara Anggota dan Non-anggota
Operator biner
=
(penugasan),[]
(langganan langganan),->
(akses anggota), serta()
operator n-ary (panggilan fungsi), harus selalu diimplementasikan sebagai fungsi anggota , karena sintaks bahasa mengharuskannya.Operator lain dapat diimplementasikan sebagai anggota atau bukan anggota. Beberapa dari mereka, bagaimanapun, biasanya harus diimplementasikan sebagai fungsi non-anggota, karena operan kiri mereka tidak dapat dimodifikasi oleh Anda. Yang paling menonjol dari ini adalah operator input dan output
<<
dan>>
, yang operan kirinya adalah kelas aliran dari perpustakaan standar yang tidak dapat Anda ubah.Untuk semua operator di mana Anda harus memilih untuk mengimplementasikannya sebagai fungsi anggota atau fungsi bukan anggota, gunakan aturan praktis berikut untuk memutuskan:
Tentu saja, seperti semua aturan praktis lainnya, ada pengecualian. Jika Anda memiliki tipe
dan Anda ingin membebani operator kenaikan dan penurunan secara berlebihan, Anda tidak dapat melakukan ini sebagai fungsi anggota, karena di C ++, tipe enum tidak dapat memiliki fungsi anggota. Jadi, Anda harus membebani itu sebagai fungsi gratis. Dan
operator<()
untuk templat kelas yang bersarang di dalam templat kelas jauh lebih mudah untuk menulis dan membaca bila dilakukan sebagai fungsi anggota sebaris dalam definisi kelas. Tapi ini memang pengecualian yang jarang.(Namun, jika Anda membuat pengecualian, jangan lupa masalah
const
-ness untuk operan yang, untuk fungsi anggota, menjadithis
argumen implisit . Jika operator sebagai fungsi non-anggota akan mengambil argumen paling kiri sebagaiconst
referensi , operator yang sama sebagai fungsi anggota perlu memilikiconst
di akhir untuk membuat*this
sebuahconst
referensi.)Lanjutkan ke Operator umum untuk melakukan overload .
sumber
operator+=()
tidak menjadi anggota. Ia harus mengubah operan tangan kirinya, jadi menurut definisi ia harus menggali lebih dalam ke jeroan. Apa yang akan Anda dapatkan dengan tidak menjadikannya anggota?operator +=
dan keduanyaappend
. Theappend
Metode ini lebih lengkap, karena Anda dapat menambahkan sebuah substring parameter dari indeks i indeks n -1:append(string, start, end)
Tampaknya logis untuk memiliki+=
panggilan append denganstart = 0
danend = string.size
. Pada saat itu, append dapat menjadi metode anggota, tetapioperator +=
tidak perlu menjadi anggota, dan menjadikannya non-anggota akan mengurangi jumlah bermain kode dengan String dalam, jadi itu adalah hal yang baik .... ^ _ ^ ...Operator Konversi (juga dikenal sebagai Konversi Buatan Pengguna)
Di C ++ Anda dapat membuat operator konversi, operator yang memungkinkan kompiler untuk mengkonversi antara tipe Anda dan tipe yang ditentukan lainnya. Ada dua jenis operator konversi, yang implisit dan eksplisit.
Operator Konversi Tersirat (C ++ 98 / C ++ 03 dan C ++ 11)
Operator konversi implisit memungkinkan kompiler untuk secara implisit mengkonversi (seperti konversi antara
int
danlong
) nilai tipe yang ditentukan pengguna ke beberapa tipe lainnya.Berikut ini adalah kelas sederhana dengan operator konversi implisit:
Operator konversi tersirat, seperti konstruktor satu argumen, adalah konversi yang ditentukan pengguna. Kompiler akan memberikan satu konversi yang ditentukan pengguna ketika mencoba mencocokkan panggilan ke fungsi yang kelebihan beban.
Pada awalnya ini tampaknya sangat membantu, tetapi masalah dengan ini adalah bahwa konversi implisit bahkan menendang ketika itu tidak diharapkan. Dalam kode berikut,
void f(const char*)
akan dipanggil karenamy_string()
bukan nilai , jadi yang pertama tidak cocok:Pemula dengan mudah mendapatkan kesalahan ini dan bahkan programmer C ++ yang berpengalaman terkadang terkejut karena kompiler mengambil kelebihan yang tidak mereka duga. Masalah-masalah ini dapat dikurangi oleh operator konversi eksplisit.
Operator Konversi Eksplisit (C ++ 11)
Tidak seperti operator konversi implisit, operator konversi eksplisit tidak akan pernah memulai ketika Anda tidak mengharapkannya. Berikut ini adalah kelas sederhana dengan operator konversi eksplisit:
Perhatikan
explicit
. Sekarang ketika Anda mencoba untuk mengeksekusi kode yang tidak terduga dari operator konversi implisit, Anda mendapatkan kesalahan kompilator:Untuk memanggil operator pemeran eksplisit, Anda harus menggunakan
static_cast
, pemeran gaya-C, atau pemain gaya konstruktor (yaituT(value)
).Namun, ada satu pengecualian untuk ini: Kompiler diizinkan untuk secara implisit dikonversi ke
bool
. Selain itu, kompiler tidak diperbolehkan untuk melakukan konversi implisit lain setelah dikonversi menjadibool
(kompiler diperbolehkan untuk melakukan 2 konversi implisit sekaligus, tetapi hanya 1 konversi yang ditentukan pengguna pada maks).Karena kompiler tidak akan menampilkan "masa lalu"
bool
, operator konversi eksplisit sekarang menghapus kebutuhan akan idiom Bool Aman . Misalnya, pointer cerdas sebelum C ++ 11 menggunakan idiom Safe Bool untuk mencegah konversi ke tipe integral. Dalam C ++ 11, smart pointer menggunakan operator eksplisit karena compiler tidak diperbolehkan untuk secara implisit mengkonversi ke tipe integral setelah secara eksplisit mengkonversi tipe menjadi bool.Lanjutkan ke Overloading
new
dandelete
.sumber
Overloading
new
dandelete
Catatan: Ini hanya berkaitan dengan sintaks kelebihan muatan
new
dandelete
, bukan dengan implementasi dari operator kelebihan beban tersebut. Saya pikir semantik overloadingnew
dandelete
layak mendapatkan FAQ mereka sendiri , dalam topik overloading operator saya tidak pernah bisa melakukannya dengan adil.Dasar-dasar
Di C ++, ketika Anda menulis ekspresi baru seperti
new T(arg)
dua hal terjadi ketika ekspresi ini dievaluasi: Pertamaoperator new
dipanggil untuk mendapatkan memori mentah, dan kemudian konstruktor yang sesuaiT
dipanggil untuk mengubah memori mentah ini menjadi objek yang valid. Demikian juga, ketika Anda menghapus objek, pertama-tama destruktornya dipanggil, dan kemudian memori dikembalikan keoperator delete
.C ++ memungkinkan Anda untuk menyempurnakan kedua operasi ini: manajemen memori dan konstruksi / penghancuran objek pada memori yang dialokasikan. Yang terakhir dilakukan dengan menulis konstruktor dan destruktor untuk suatu kelas. Pengaturan memori yang baik dilakukan dengan menulis sendiri
operator new
danoperator delete
.Yang pertama dari aturan dasar overloading operator - jangan lakukan itu - berlaku terutama untuk overloading
new
dandelete
. Hampir satu-satunya alasan untuk membebani operator ini adalah masalah kinerja dan kendala memori , dan dalam banyak kasus, tindakan lain, seperti perubahan pada algoritma yang digunakan, akan memberikan rasio biaya / keuntungan yang jauh lebih tinggi daripada mencoba mengubah manajemen memori.Pustaka standar C ++ dilengkapi dengan seperangkat yang telah ditentukan
new
dandelete
operator. Yang paling penting adalah ini:Dua yang pertama mengalokasikan / membatalkan alokasi memori untuk suatu objek, dua yang terakhir untuk array objek. Jika Anda memberikan versi Anda sendiri dari ini, mereka tidak akan kelebihan beban, tetapi ganti yang dari perpustakaan standar.
Jika Anda kelebihan beban
operator new
, Anda harus selalu juga membebani pencocokanoperator delete
, bahkan jika Anda tidak pernah bermaksud menyebutnya. Alasannya adalah, jika konstruktor melempar selama evaluasi ekspresi baru, sistem run-time akan mengembalikan memori keoperator delete
pencocokanoperator new
yang dipanggil untuk mengalokasikan memori untuk membuat objek. Jika Anda tidak memberikan pencocokanoperator delete
, yang standar disebut, yang hampir selalu salah.Jika Anda kelebihan
new
dandelete
, Anda harus mempertimbangkan kelebihan varian array juga.Penempatan
new
C ++ memungkinkan operator baru dan menghapus untuk mengambil argumen tambahan.
Apa yang disebut penempatan baru memungkinkan Anda membuat objek di alamat tertentu yang diteruskan ke:
Pustaka standar dilengkapi dengan kelebihan yang tepat dari operator baru dan hapus untuk ini:
Perhatikan bahwa, dalam kode contoh untuk penempatan yang baru diberikan di atas,
operator delete
tidak pernah dipanggil, kecuali jika konstruktor X melempar pengecualian.Anda juga bisa kelebihan beban
new
dandelete
dengan argumen lain. Seperti argumen tambahan untuk penempatan baru, argumen ini juga tercantum dalam tanda kurung setelah kata kuncinew
. Hanya karena alasan historis, varian seperti itu sering juga disebut penempatan baru, bahkan jika argumennya bukan untuk menempatkan objek pada alamat tertentu.Khusus kelas baru dan hapus
Paling umum Anda akan ingin menyempurnakan manajemen memori karena pengukuran telah menunjukkan bahwa instance kelas tertentu, atau sekelompok kelas terkait, sering dibuat dan dihancurkan dan bahwa manajemen memori default sistem run-time, disesuaikan untuk kinerja umum, berurusan secara tidak efisien dalam kasus khusus ini. Untuk meningkatkan ini, Anda dapat membebani yang baru dan menghapus untuk kelas tertentu:
Kelebihan itu, baru dan hapus berperilaku seperti fungsi anggota statis. Untuk objek dari
my_class
,std::size_t
argumennya akan selalusizeof(my_class)
. Namun, operator ini juga dipanggil untuk objek yang diturunkan secara dinamis dari kelas turunan , dalam hal ini mungkin lebih besar dari itu.Global baru dan hapus
Untuk membebani global baru dan menghapus, cukup ganti operator standar perpustakaan dengan milik kami. Namun, hal ini jarang perlu dilakukan.
sumber
nothrow
baru.Mengapa tidak bisa
operator<<
berfungsi untuk streaming objek kestd::cout
atau ke file menjadi fungsi anggota?Katakanlah Anda memiliki:
Karena itu, Anda tidak dapat menggunakan:
Karena
operator<<
kelebihan beban sebagai fungsi anggotaFoo
, LHS operator harus menjadiFoo
objek. Yang berarti, Anda akan diminta untuk menggunakan:yang sangat tidak intuitif.
Jika Anda mendefinisikannya sebagai fungsi non-anggota,
Anda akan dapat menggunakan:
yang sangat intuitif.
sumber