Kode kita sudah sering bertukar nilai antar tipe tanpa kita sadari: char masuk ke int, int bergabung dengan double, dan compiler hanya diam dan menuruti. Proses itu disebut konversi tipe (type conversion), dan C++ menjalankannya di dua jalur: secara implisit — otomatis oleh compiler mengikuti aturan standar — atau secara eksplisit lewat static_cast ketika kita yang memerintahkan. Jalur implisit menghemat penulisan tetapi kadang membuang data tanpa suara; jalur eksplisit sedikit lebih panjang, tetapi niatnya terdokumentasi di kode. Chapter ini memetakan kapan konversi aman, kapan kehilangan data, dan mengapa static_cast menjadi alat pilihan C++ modern.

Konversi Implisit dan Integer Division #

Aturan bakunya: konversi dari tipe “kecil” ke tipe “besar” (misalnya int ke double) biasanya aman karena tidak ada nilai yang hilang; sebaliknya, konversi dari tipe besar ke kecil bisa memotong data. Compiler juga menerapkan promotion: dalam ekspresi campuran, char dan short otomatis naik menjadi int, dan saat int bertemu double, keduanya dikerjakan dalam double. Program berikut memperlihatkan akibat praktisnya — termasuk satu jebakan terkenal bernama integer division:

cpp
#include <iostream>

int main() {
    // Integer division dulu, baru hasilnya disimpan ke double
    double rataSalah = 19 / 4;      // 19 / 4 = 4 (int), lalu jadi 4.0
    double rataBenar = 19.0 / 4;    // promotion: 4 naik kelas menjadi double

    // static_cast: menyatakan konversi secara eksplisit
    int totalPoin = 17;
    int jumlahSiswa = 4;
    double rataPoin = static_cast<double>(totalPoin) / jumlahSiswa;

    // Konversi implisit saat assignment: double -> int terpotong
    int implisit = 3.99;            // lolos tanpa suara: 3

    // static_cast dengan niat yang sama, kini terlihat gamblang
    int eksplisit = static_cast<int>(3.99);

    // C-style cast: gaya lama warisan bahasa C
    double gayaLama = (double)totalPoin / jumlahSiswa;

    std::cout << "19 / 4              = " << rataSalah << "\n";
    std::cout << "19.0 / 4            = " << rataBenar << "\n";
    std::cout << "static_cast<double> = " << rataPoin << "\n";
    std::cout << "implisit  3.99 ->   = " << implisit << "\n";
    std::cout << "eksplisit 3.99 ->   = " << eksplisit << "\n";
    std::cout << "(double) totalPoin  = " << gayaLama << "\n";

    return 0;
}

Output yang Dihasilkan:

text
19 / 4              = 4
19.0 / 4            = 4.75
static_cast<double> = 4.25
implisit  3.99 ->   = 3
eksplisit 3.99 ->   = 3
(double) totalPoin  = 4.25

Baris demi baris yang menentukan:

  1. Baris 7 (double rataSalah = 19 / 4;): pembagian dua int dilakukan lebih dulu dalam dunia integer, menghasilkan 4 (sisa 3 dibuang), baru kemudian disimpan ke double sebagai 4.0. Tipe tujuan tidak mengubah perhitungan yang sudah selesai — inilah jebakan integer division yang klasik.
  2. Baris 8 (19.0 / 4): satu operand dibuat double, sehingga promotion menaikkan 4 menjadi 4.0 dan pembagian berjalan pecahan: 4.75.
  3. Baris 12 (static_cast<double>(totalPoin) / jumlahSiswa): solusi resmi C++ untuk kasus di atas — kita meminta totalPoin didobelkan sebelum dibagi, menghasilkan rata-rata benar 4.25.
  4. Baris 15 vs 18: kedua baris menghasilkan 3 dari 3.99. Yang pertama terjadi tanpa jejak di kode; yang kedua menuliskan niatnya dengan gamblang — pembaca langsung tahu pemotongan itu disengaja, bukan bug.

static_cast: Menyatakan Konversi secara Eksplisit #

Sintaksnya agak panjang: static_cast<tipe_tujuan>(nilai). Bentuk kata kerja ini disengaja — konversi yang berisiko harus terlihat seperti apa adanya, mudah dicari dengan teks static_cast, dan tidak tersamar dengan panggilan fungsi biasa. static_cast adalah konversi yang diaudit compiler: hanya aturan konversi yang memang sah menurut standar yang boleh lewat, dan bila konversinya mustahil (misalnya static_cast<int>("teks")), compiler menolaknya alih-alih diam-diam menambahkan perilaku aneh.

Perlu diketahui ada empat bentuk cast di C++ modern — static_cast, const_cast, reinterpret_cast, dan dynamic_cast — masing-masing dengan wewenang berbeda; tiga terakhir baru masuk akal setelah kita mempelajari pointer, class, dan inheritance di section-section berikutnya. Untuk semua kebutuhan konversi tipe biasa, static_cast adalah jawabannya.

C-Style Cast dan Mengapa Dihindari #

Baris terakhir program memakai (double)totalPoin — bentuk warisan bahasa C yang masih sah dan banyak ditemui di kode lama. Masalahnya, cast gaya C ini “serba bisa”: compiler mencoba serangkaian aturan konversi secara diam-diam hingga ada yang lolos, termasuk konversi berbahaya yang seharusnya memakai reinterpret_cast. Karena itu satu baris (T)x bisa menyembunyikan niat yang sangat berbeda, dan pencarian teks (T) di kode juga lebih mudah meleset. Guideline modern (termasuk C++ Core Guidelines ) menyarankan memilih bentuk bernama: eksplisit, dapat diaudit, dan sengaja dibuat tidak nyaman supaya dipakai seperlunya.

Kapan Aman, Kapan Kehilangan Data #

Arah konversiStatusCatatan
char/short → intamanpromotion; tidak ada nilai yang hilang
int → doublehampir amanbilangan besar (lebih dari 2⁵³) mulai kehilangan ketelitian
float → doubleamanpresisi justru bertambah
double → intkehilangan databagian pecahan dibuang (truncation), bukan dibulatkan
double → floatkehilangan presisidigit di luar kapasitas float dibulatkan
long long → intkehilangan databit di luar 32 bit dibuang; bisa berubah total

Tabel ini menegaskan pola besarnya: naik kelas biasanya selamat, turun kelas perlu alasan yang tertulis. Bagian “kecil ke besar” pun punya catatan kaki untuk unsigned yang sudah kita kenal: int negatif yang dikonversi ke unsigned int menghasilkan angka raksasa — perilaku terdefinisi, tetapi hampir pasti bukan yang kita maksud.

Salah satu konversi paling berisiko dari tabel di atas — konversi yang membuat nilai berubah diam-diam — sebenarnya bisa dimatikan total oleh compiler. Mekanismenya menyangkut bentuk inisialisasi kurung kurawal dari Chapter Inisialisasi Variabel, dan itulah topik penuh Chapter berikutnya: narrowing conversion.

Rujukan resmi untuk topik Chapter ini: implicit conversions dan explicit type conversion di cppreference.