C ++ memiliki fitur (saya tidak tahu nama yang tepat), yang secara otomatis memanggil konstruktor yang cocok dari tipe parameter jika tipe argumen bukan yang diharapkan.
Contoh yang sangat mendasar dari hal ini adalah memanggil fungsi yang mengharapkan a std::string
dengan const char*
argumen. Kompiler akan secara otomatis menghasilkan kode untuk memanggil std::string
konstruktor yang sesuai .
Saya bertanya-tanya, apakah buruk untuk keterbacaan seperti yang saya kira?
Ini sebuah contoh:
class Texture {
public:
Texture(const std::string& imageFile);
};
class Renderer {
public:
void Draw(const Texture& texture);
};
Renderer renderer;
std::string path = "foo.png";
renderer.Draw(path);
Apakah itu baik-baik saja? Atau apakah itu terlalu jauh? Jika saya tidak melakukannya, bisakah saya membuat Dentang atau GCC memperingatkan tentang hal itu?
Jawaban:
Ini disebut sebagai konstruktor pengonversi (atau terkadang konstruktor implisit atau konversi implisit).
Saya tidak mengetahui pergantian waktu kompilasi untuk memperingatkan ketika ini terjadi, tetapi sangat mudah untuk dicegah; cukup gunakan
explicit
kata kunci.Seperti apakah mengkonversi konstruktor adalah ide yang baik: Itu tergantung.
Keadaan di mana konversi implisit masuk akal:
std::string
merefleksikan konsep yang sama dengan yangconst char *
secara implisit dapat dikonversi dari), sehingga konversi implisit masuk akal.Keadaan di mana konversi implisit kurang masuk akal:
AnsiString
kelas tidak boleh membangun secara implisit dari aUnicodeString
, karena konversi Unicode-ke-ANSI dapat kehilangan informasi.Bacaan lebih lanjut:
sumber
Ini lebih dari komentar daripada jawaban tetapi terlalu besar untuk dimasukkan ke dalam komentar.
Menariknya,
g++
jangan biarkan saya melakukan itu:Menghasilkan yang berikut:
Namun, jika saya mengubah jalur ke:
Itu akan melakukan konversi itu.
sumber
gcc
opsi kompiler (yang sepertinya tidak ada untuk mengatasi kasus khusus ini). Saya tidak melihat lebih jauh ke dalamnya (saya seharusnya bekerja :-) tetapi mengingatgcc
kepatuhan terhadap standar dan penggunaanexplicit
kata kunci, opsi kompiler mungkin dianggap tidak perlu.Texture
mungkin seharusnya tidak dibangun secara implisit (sesuai dengan pedoman dalam jawaban lain), jadi situs panggilan yang lebih baik adalahrenderer.Draw(Texture("foo.png"));
(dengan asumsi itu berfungsi seperti yang saya harapkan).Ini disebut konversi tipe implisit. Secara umum itu adalah hal yang baik, karena menghambat pengulangan yang tidak perlu. Misalnya, Anda secara otomatis mendapatkan
std::string
versiDraw
tanpa harus menulis kode tambahan apa pun untuknya. Ini juga dapat membantu dalam mengikuti prinsip buka-tutup, karena memungkinkan Anda memperluasRenderer
kemampuan tanpa memodifikasiRenderer
sendiri.Di sisi lain, ini bukan tanpa kekurangan. Ini bisa menyulitkan untuk mencari tahu dari mana argumen berasal, untuk satu hal. Kadang-kadang dapat menghasilkan hasil yang tidak terduga dalam kasus lain. Untuk itulah
explicit
kata kunci tersebut. Jika Anda meletakkannya diTexture
konstruktor itu dinonaktifkan menggunakan konstruktor itu untuk konversi tipe implisit. Saya tidak mengetahui metode untuk memperingatkan global tentang konversi tipe implisit, tetapi itu tidak berarti metode tidak ada, hanya bahwa gcc memiliki sejumlah besar opsi yang tidak dapat dipahami.sumber