Jika Anda bertanya kepada programmer C ++ tentang arti kata kunci eksplisit, sebagian besar akan menjawab bahwa kata kunci ini ditempatkan sebelum deklarasi konstruktor dengan satu parameter (atau dengan sejumlah besar parameter, tetapi ketika semua parameter, mulai dari yang kedua, memiliki nilai default) dan mencegah konversi implisit jenis pada inisialisasi.
class Simple { public: Simple(int a) : a_(a) {} private: int a_; }; class SimpleExplicit { public: explicit SimpleExplicit(int a) : a_(a) {} private: int a_; }; template <typename S> void someFunc(const S& s) { } int main(int, char**) { Simple s3 = 11; // SimpleExplicit se3 = 11; - COMPILE ERROR SimpleExplicit se3 = SimpleExplicit(11); someFunc<Simple>(11); // someFunc<SimpleExplicit>(11); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit(11)); return 0; }
Dalam C ++ 03 tua yang baik, skenario aplikasi kata kunci berakhir di sana, namun, dimulai dengan C ++ 11, cakupan eksplisit diperluas: sekarang masuk akal tidak hanya dalam konstruktor dengan satu parameter, dan bahkan tidak hanya dalam konstruktor.
Pada tahun 2011, Standard menambahkan inisialisasi seragam, yang harus membersihkan metode kebun binatang untuk menginisialisasi objek yang diwarisi dari C ++. Saya tidak akan berbicara secara rinci tentang inisialisasi universal di sini, ada banyak artikel rinci tentang hal ini, mereka mudah ditemukan dengan kata kunci. Singkatnya: objek diusulkan untuk diinisialisasi menggunakan kurung kurawal, pada kenyataannya ekstensi ini adalah apa yang disebut inisialisasi agregat yang diwarisi dari C.
Dengan munculnya inisialisasi universal, eksplisit masuk akal untuk desainer dengan parameter 0,2,3 atau lebih:
class Simple { public: Simple() : a_(0), b_(0) {} Simple(int a) : a_(a), b_(0) {} Simple(int a, int b) : a_(a), b_(b) {} private: int a_, b_; }; class SimpleExplicit { public: explicit SimpleExplicit() : a_(0), b_(0) {} explicit SimpleExplicit(int a) : a_(a), b_(0) {} explicit SimpleExplicit(int a, int b) : a_(a), b_(b) {} private: int a_, b_; }; template <typename S> void someFunc(const S& s) { } int main(int, char**) { Simple s4 = {}; someFunc<Simple>({}); // SimpleExplicit se4 = {}; - COMPILE ERROR SimpleExplicit se4 = SimpleExplicit{}; // someFunc<SimpleExplicit>({}); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit{}); Simple s5 = {11}; someFunc<Simple>({11}); // SimpleExplicit se5 = {11}; - COMPILE ERROR SimpleExplicit se5 = SimpleExplicit{11}; // someFunc<SimpleExplicit>({11}); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit{11}); Simple s6 = {11, 22}; someFunc<Simple>({11, 22}); // SimpleExplicit se6 = {11, 22}; - COMPILE ERROR SimpleExplicit se6 = SimpleExplicit{11, 22}; // someFunc<SimpleExplicit>({11, 22}); - COMPILE ERROR someFunc<SimpleExplicit>(SimpleExplicit{11, 22}); return 0; }
Selain itu, dimulai dengan C ++ 11, kata kunci eksplisit juga dapat diterapkan untuk mengetik operator konversi, juga melarang permintaan implisit mereka:
class Simple { public: Simple() {} operator bool() const { return true; } }; class SimpleExplicit { public: explicit SimpleExplicit() {} explicit operator bool() const { return true; } }; int main(int, char**) { Simple s7{}; bool b7 = s7; SimpleExplicit se7{}; // bool be7 = se7; - COMPILE ERROR bool be7 = static_cast<bool>(se7); return 0; }
Sebagai kesimpulan, saya ingin merekomendasikan menggunakan inisialisasi universal dalam kode C ++ baru, serta secara eksplisit mendeklarasikan konstruktor eksplisit selalu, kecuali konversi implisit dibenarkan secara semantik.