Tidak ada cinta C ++ dalam hal "fitur tersembunyi" pertanyaan? Kupikir aku akan membuangnya ke sana. Apa sajakah fitur tersembunyi dari C ++?
c++
hidden-features
Craig H.
sumber
sumber
Jawaban:
Kebanyakan programmer C ++ sudah familiar dengan operator terner:
Namun, mereka tidak menyadari bahwa ini dapat digunakan sebagai nilai l:
yang merupakan singkatan dari
Gunakan dengan hati-hati :-)
sumber
(value ? function1 : function2)()
.function1
danfunction2
secara implisit dikonversi ke pointer fungsi, dan hasilnya secara implisit diubah kembali.Anda dapat menempatkan URI ke dalam sumber C ++ tanpa kesalahan. Sebagai contoh:
sumber
goto
, yang memang dimiliki C ++). Apa pun setelah dua garis miring adalah sebuah komentar. Oleh karena itu, denganhttp://stackoverflow.com
,http
adalah label (Anda secara teoritis dapat menulisgoto http;
), dan//stackoverflow.com
hanya komentar akhir baris. Keduanya adalah C ++ legal, sehingga konstruk dikompilasi. Itu tidak melakukan sesuatu yang samar-samar berguna, tentu saja.goto http;
sebenarnya tidak mengikuti URL. :(Pemrogram C ++ lebih suka menghindari petunjuk karena bug yang dapat diperkenalkan.
C ++ paling keren yang pernah saya lihat? Literal analog.
sumber
Saya setuju dengan sebagian besar posting di sana: C ++ adalah bahasa multi-paradigma, jadi fitur "tersembunyi" yang akan Anda temukan (selain "perilaku tidak terdefinisi" yang harus Anda hindari dengan cara apa pun) adalah penggunaan fasilitas yang cerdas.
Sebagian besar fasilitas tersebut bukanlah fitur bawaan bahasa, tetapi yang berbasis perpustakaan.
Yang paling penting adalah RAII , sering diabaikan selama bertahun-tahun oleh pengembang C ++ yang berasal dari dunia C. Kelebihan beban operator sering kali merupakan fitur yang disalahpahami yang memungkinkan perilaku seperti array (operator subskrip), operasi seperti penunjuk (penunjuk cerdas), dan operasi serupa build-in (mengalikan matriks.
Penggunaan pengecualian sering kali sulit, tetapi dengan beberapa pekerjaan, dapat menghasilkan kode yang sangat kuat melalui spesifikasi keselamatan pengecualian (termasuk kode yang tidak akan gagal, atau yang akan memiliki fitur seperti commit yang akan berhasil, atau kembali ke keadaan aslinya).
Fitur "tersembunyi" yang paling terkenal dari C ++ adalah metaprogramming template , karena fitur ini memungkinkan Anda menjalankan sebagian (atau seluruhnya) program Anda pada waktu kompilasi, bukan pada waktu proses. Ini sulit, dan Anda harus memiliki pemahaman yang kuat tentang templat sebelum mencobanya.
Orang lain menggunakan beberapa paradigma untuk menghasilkan "cara pemrograman" di luar leluhur C ++, yaitu C.
Dengan menggunakan functors , Anda dapat mensimulasikan fungsi, dengan keamanan tipe tambahan dan menjadi stateful. Dengan menggunakan pola perintah , Anda dapat menunda eksekusi kode. Kebanyakan pola desain lainnya dapat dengan mudah dan efisien diimplementasikan dalam C ++ untuk menghasilkan gaya pengkodean alternatif yang tidak seharusnya berada di dalam daftar "paradigma C ++ resmi".
Dengan menggunakan templat , Anda dapat menghasilkan kode yang akan berfungsi pada sebagian besar jenis, termasuk bukan yang Anda pikirkan pada awalnya. Anda juga dapat meningkatkan keamanan tipe (seperti malloc aman jenis otomatis / realloc / free). Fitur objek C ++ sangat kuat (dan karenanya, berbahaya jika digunakan secara sembarangan), tetapi polimorfisme dinamis pun memiliki versi statisnya di C ++: CRTP .
Saya telah menemukan bahwa sebagian besar buku jenis " C ++ Efektif " dari Scott Meyers atau buku jenis " C ++ Luar Biasa " dari Herb Sutter mudah dibaca, dan cukup berharga untuk info tentang fitur C ++ yang dikenal dan kurang dikenal.
Di antara pilihan saya adalah salah satu yang harus membuat rambut setiap programmer Java bangkit dari horor: Dalam C ++, cara paling berorientasi objek untuk menambahkan fitur ke objek adalah melalui fungsi non-anggota non-teman, daripada anggota- fungsi (yaitu metode kelas), karena:
Dalam C ++, antarmuka kelas adalah fungsi-anggota dan fungsi non-anggota dalam namespace yang sama
fungsi non-teman non-anggota tidak memiliki akses istimewa ke internal kelas. Dengan demikian, menggunakan fungsi anggota di atas non-anggota non-teman akan melemahkan enkapsulasi kelas.
Ini tidak pernah gagal untuk mengejutkan bahkan pengembang berpengalaman.
(Sumber: Antara lain, Guru online Herb Sutter minggu ini # 84: http://www.gotw.ca/gotw/084.htm )
sumber
Salah satu fitur bahasa yang saya anggap agak tersembunyi, karena saya belum pernah mendengarnya sepanjang waktu saya di sekolah, adalah alias namespace. Itu tidak menarik perhatian saya sampai saya menemukan contohnya di dokumentasi pendorong. Tentu saja, setelah saya mengetahuinya, Anda dapat menemukannya di referensi C ++ standar apa pun.
sumber
using
.Variabel tidak hanya dapat dideklarasikan di bagian init dari sebuah
for
loop, tetapi juga kelas dan fungsi.Itu memungkinkan banyak variabel dengan jenis yang berbeda.
sumber
Operator array bersifat asosiatif.
A [8] adalah sinonim untuk * (A + 8). Karena penjumlahan bersifat asosiatif, itu dapat ditulis ulang sebagai * (8 + A), yang merupakan sinonim untuk ..... 8 [A]
Anda tidak mengatakan berguna ... :-)
sumber
A
tidak penting sama sekali. Misalnya, jikaA
achar*
, kode tersebut akan tetap valid.Satu hal yang sedikit diketahui adalah bahwa serikat pekerja juga dapat menjadi templat:
Dan mereka juga dapat memiliki konstruktor dan fungsi anggota. Tidak ada yang ada hubungannya dengan warisan (termasuk fungsi virtual).
sumber
From
danTo
disetel serta digunakan dengan semestinya . Gabungan semacam itu dapat digunakan dengan perilaku yang ditentukan (denganTo
menjadi sebuah array dari unsigned char atau struct berbagi urutan awal denganFrom
). Meskipun Anda menggunakannya dengan cara yang tidak ditentukan, ini mungkin masih berguna untuk pekerjaan tingkat rendah. Bagaimanapun, ini hanyalah salah satu contoh template serikat - mungkin ada kegunaan lain untuk serikat yang memiliki template.C ++ adalah bahasa multi-paradigma, Anda dapat mempertaruhkan uang terakhir Anda karena ada fitur tersembunyi. Satu contoh dari banyak: metaprogramming template . Tak seorang pun di komite standar bermaksud agar ada sub-bahasa Turing-complete yang dijalankan pada waktu kompilasi.
sumber
Fitur tersembunyi lainnya yang tidak berfungsi di C adalah fungsionalitas unary
+
operator . Anda dapat menggunakannya untuk mempromosikan dan merusak segala macam halMengonversi Enumerasi menjadi integer
Dan nilai pencacah Anda yang sebelumnya memiliki tipe pencacahan sekarang memiliki tipe bilangan bulat sempurna yang sesuai dengan nilainya. Secara manual, Anda tidak akan tahu tipe itu! Ini diperlukan misalnya ketika Anda ingin menerapkan operator yang kelebihan beban untuk enumerasi Anda.
Dapatkan nilai dari variabel
Anda harus menggunakan kelas yang menggunakan penginisialisasi statis dalam kelas tanpa definisi di luar kelas, tetapi terkadang gagal untuk menautkan? Operator dapat membantu membuat sementara tanpa membuat asumsi atau ketergantungan pada tipenya
Merusak array menjadi pointer
Apakah Anda ingin meneruskan dua pointer ke suatu fungsi, tetapi tidak berhasil? Operator mungkin membantu
sumber
Masa hidup temporer yang terikat pada referensi konst adalah salah satu yang hanya diketahui sedikit orang. Atau setidaknya itu adalah pengetahuan C ++ favorit saya yang tidak diketahui kebanyakan orang.
sumber
Fitur bagus yang jarang digunakan adalah blok coba-tangkap di seluruh fungsi:
Penggunaan utama akan menerjemahkan pengecualian ke kelas pengecualian lain dan memutar ulang, atau untuk menerjemahkan antara pengecualian dan penanganan kode kesalahan berbasis kembali.
sumber
return
menangkap blok dari Coba Fungsi, hanya lempar ulang.Banyak yang tahu tentang
identity
/id
metafunction, tetapi ada kasus penggunaan yang bagus untuknya untuk kasus non-template: Kemudahan menulis deklarasi:Ini sangat membantu mendekripsi dekripsi C ++!
sumber
template<typename Ret,typename... Args> using function = Ret (Args...); template<typename T> using pointer = *T;
->pointer<function<void,int>> f(pointer<function<void,void>>);
ataupointer<void(int)> f(pointer<void()>);
ataufunction<pointer<function<void,int>>,pointer<function<void,void>>> f;
Fitur yang cukup tersembunyi adalah Anda dapat mendefinisikan variabel dalam kondisi if, dan cakupannya hanya akan mencakup if, dan blok else:
Beberapa makro menggunakannya, misalnya untuk menyediakan beberapa cakupan "terkunci" seperti ini:
BOOST_FOREACH juga menggunakannya di bawah tenda. Untuk menyelesaikan ini, tidak hanya mungkin di jika, tetapi juga di sakelar:
dan dalam beberapa saat:
(dan juga dalam kondisi untuk). Tapi saya tidak terlalu yakin apakah ini semua berguna :)
sumber
if((a = f()) == b) ...
, tetapi jawaban ini sebenarnya menyatakan variabel dalam kondisi tersebut.for(...; int i = foo(); ) ...;
This akan melewati body selamai
true, menginisialisasinya setiap kali lagi. Perulangan yang Anda perlihatkan hanya mendemonstrasikan deklarasi variabel, tetapi bukan deklarasi variabel yang secara bersamaan bertindak sebagai kondisi :)Mencegah operator koma memanggil operator kelebihan beban
Kadang-kadang Anda menggunakan operator koma yang valid, tetapi Anda ingin memastikan bahwa tidak ada operator koma yang ditentukan pengguna yang menghalangi, karena misalnya Anda mengandalkan titik urutan antara sisi kiri dan kanan atau ingin memastikan tidak ada yang mengganggu yang diinginkan tindakan. Di sinilah
void()
masuk ke dalam permainan:Abaikan placeholder yang saya masukkan untuk kondisi dan kode. Yang penting adalah
void()
, yang membuat kompilator memaksa untuk menggunakan operator koma bawaan. Ini bisa berguna saat mengimplementasikan kelas ciri, terkadang juga.sumber
Inisialisasi array dalam konstruktor. Misalnya di kelas jika kita memiliki array
int
sebagai:Kita dapat menginisialisasi semua elemen dalam array ke default-nya (di sini semua elemen array menjadi nol) di konstruktor sebagai:
sumber
Oooh, saya bisa membuat daftar kebencian hewan peliharaan sebagai gantinya:
Di sisi positifnya
sumber
Anda dapat mengakses data yang dilindungi dan anggota fungsi dari kelas mana pun, tanpa perilaku yang tidak ditentukan, dan dengan semantik yang diharapkan. Baca terus untuk mengetahui caranya. Baca juga laporan kerusakan tentang ini.
Biasanya, C ++ melarang Anda untuk mengakses anggota kelas yang dilindungi non-statis, meskipun kelas itu adalah kelas dasar Anda.
Itu dilarang: Anda dan kompilator tidak tahu apa yang sebenarnya ditunjukkan oleh referensi tersebut. Ini bisa menjadi
C
objek, di mana kelasB
tidak memiliki bisnis dan petunjuk tentang datanya. Akses tersebut hanya diberikan jikax
merupakan referensi ke kelas turunan atau turunan darinya. Dan itu dapat memungkinkan bagian kode yang berubah-ubah membaca setiap anggota yang dilindungi hanya dengan membuat kelas "membuang" yang membacakan anggota, misalnyastd::stack
:Tentunya, seperti yang Anda lihat ini akan menyebabkan terlalu banyak kerusakan. Tapi sekarang, petunjuk anggota memungkinkan menghindari perlindungan ini! Poin kuncinya adalah bahwa jenis penunjuk anggota terikat ke kelas yang sebenarnya berisi anggota tersebut - bukan ke kelas yang Anda tentukan saat mengambil alamat. Ini memungkinkan kami untuk menghindari pemeriksaan
Dan tentu saja, ini juga berfungsi dengan
std::stack
contoh.Itu akan menjadi lebih mudah dengan menggunakan deklarasi di kelas turunan, yang membuat nama anggota menjadi publik dan merujuk ke anggota kelas dasar.
sumber
Fitur tersembunyi lainnya adalah Anda dapat memanggil objek kelas yang dapat diubah menjadi pointer atau referensi fungsi. Resolusi kelebihan beban dilakukan berdasarkan hasil dari mereka, dan argumen diteruskan dengan sempurna.
Ini disebut "fungsi panggilan pengganti".
sumber
Fitur tersembunyi:
Jika suatu fungsi menampilkan pengecualian yang tidak tercantum dalam spesifikasi pengecualiannya, tetapi fungsi tersebut memiliki
std::bad_exception
spesifikasi pengecualiannya, pengecualian tersebut diubah menjadistd::bad_exception
dan ditampilkan secara otomatis. Dengan cara itu Anda setidaknya akan tahu bahwa adabad_exception
yang terlempar. Baca lebih lanjut di sini .fungsi coba blok
Kata kunci template dalam membedakan typedefs di template kelas. Jika nama spesialisasi anggota template yang muncul setelah
.
,->
atau::
operator, dan nama yang memiliki template parameter yang memenuhi syarat secara eksplisit, awalan nama template anggota dengan template kata kunci. Baca lebih lanjut di sini .default parameter fungsi dapat diubah saat runtime. Baca lebih lanjut di sini .
A[i]
bekerja sebaiki[A]
Contoh sementara kelas dapat dimodifikasi! Fungsi anggota non-const dapat dipanggil pada objek sementara. Sebagai contoh:
Baca lebih lanjut di sini .
Jika ada dua tipe berbeda sebelum dan sesudah ekspresi operator
:
in ternary (?:
), maka tipe ekspresi yang dihasilkan adalah yang paling umum dari keduanya. Sebagai contoh:sumber
map::operator[]
membuat entri jika kunci hilang dan mengembalikan referensi ke nilai entri yang dibuat secara default. Jadi Anda bisa menulis:Saya kagum dengan banyaknya programmer C ++ yang tidak mengetahui hal ini.
sumber
.find()
.const map::operator[]
menghasilkan pesan kesalahan"Menempatkan fungsi atau variabel dalam namespace tanpa nama akan menghentikan penggunaan
static
untuk membatasinya ke cakupan file.sumber
static
dalam lingkup global sama sekali tidak ditinggalkan. (Untuk referensi: C ++ 03 §D.2)static
penggunaan sebaiknya hanya digunakan di dalam tipe kelas atau fungsi.Mendefinisikan fungsi teman biasa di template kelas membutuhkan perhatian khusus:
Dalam contoh ini, dua contoh berbeda menciptakan dua definisi yang identik — pelanggaran langsung terhadap ODR
Oleh karena itu, kita harus memastikan parameter templat dari templat kelas muncul dalam jenis fungsi teman yang ditentukan dalam templat itu (kecuali kami ingin mencegah lebih dari satu contoh templat kelas dalam file tertentu, tetapi ini agak tidak mungkin). Mari terapkan ini ke variasi dari contoh kita sebelumnya:
Penafian: Saya telah menempelkan bagian ini dari Template C ++: Panduan Lengkap / Bagian 8.4
sumber
fungsi void dapat mengembalikan nilai void
Sedikit diketahui, tetapi kode berikut baik-baik saja
Serta yang tampak aneh berikut ini
Mengetahui hal ini, Anda dapat memanfaatkan di beberapa area. Salah satu contoh:
void
fungsi tidak dapat mengembalikan nilai tetapi Anda juga tidak dapat hanya mengembalikan apa pun, karena fungsi tersebut dapat dibuat dengan non-void. Alih-alih menyimpan nilai ke dalam variabel lokal, yang akan menyebabkan kesalahanvoid
, cukup kembalikan nilai secara langsungsumber
Membaca file menjadi vektor string:
istream_iterator
sumber
vector<string> V((istream_iterator<string>(cin)), istream_iterator<string>());
- kurung hilang setelah param keduaAnda dapat membuat template bitfield.
Saya belum menemukan tujuan apa pun untuk ini, tetapi itu pasti sangat mengejutkan saya.
sumber
Salah satu tata bahasa paling menarik dari semua bahasa pemrograman.
Tiga dari hal-hal ini menjadi satu, dan dua adalah sesuatu yang sama sekali berbeda ...
Semua kecuali yang ketiga dan kelima menentukan
SomeType
objek pada tumpukan dan menginisialisasinya (denganu
dalam dua kasus pertama, dan konstruktor default pada kasus keempat. Yang ketiga adalah mendeklarasikan fungsi yang tidak mengambil parameter dan mengembalikan aSomeType
. Yang kelima mendeklarasikan dengan cara yang sama fungsi yang mengambil satu parameter dengan nilai tipeSomeType
bernamau
.sumber
Singkirkan deklarasi maju:
Menulis pernyataan switch dengan?: Operator:
Melakukan semuanya dalam satu baris:
Mengosongkan struct tanpa memset:
Normalisasi / pembungkus nilai sudut dan waktu:
Menetapkan referensi:
sumber
FStruct s = {};
bahkan lebih pendek.main
? Saya sarankanglobal().main();
dan lupakan saja tentang singleton ( Anda bisa bekerja dengan yang sementara, yang diperpanjang seumur hidup )Operator bersyarat terner
?:
membutuhkan operan kedua dan ketiga untuk memiliki tipe yang "menyenangkan" (berbicara secara informal). Tetapi persyaratan ini memiliki satu pengecualian (permainan kata-kata): operan kedua atau ketiga dapat berupa ekspresi lemparan (yang memiliki tipevoid
), terlepas dari jenis operan lainnya.Dengan kata lain, seseorang dapat menulis ekspresi C ++ yang benar-benar valid menggunakan
?:
operatorBTW, fakta bahwa ekspresi throw sebenarnya adalah ekspresi (tipe
void
) dan bukan pernyataan adalah fitur lain yang sedikit diketahui dari bahasa C ++. Artinya, antara lain, kode berikut ini benar-benar validmeskipun tidak ada gunanya melakukannya dengan cara ini (mungkin dalam beberapa kode template umum ini mungkin berguna).
sumber
Aturan dominasi berguna, tetapi sedikit diketahui. Dikatakan bahwa meskipun dalam jalur non-unik melalui kisi kelas dasar, pencarian nama untuk anggota yang sebagian tersembunyi adalah unik jika anggota tersebut termasuk dalam kelas dasar virtual:
Saya telah menggunakan ini untuk mengimplementasikan dukungan-penyelarasan yang secara otomatis mengetahui penyelarasan paling ketat melalui aturan dominasi.
Ini tidak hanya berlaku untuk fungsi virtual, tetapi juga untuk nama typedef, anggota statis / non-virtual, dan lainnya. Saya pernah melihatnya digunakan untuk menerapkan sifat yang dapat ditimpa dalam program meta.
sumber
struct C
dalam contoh Anda ...? Bersulang.