Bagikan melalui


Sistem jenis C++

Konsep jenis penting dalam C++. Setiap variabel, argumen fungsi, dan nilai pengembalian fungsi harus memiliki jenis untuk dikompilasi. Selain itu, semua ekspresi (termasuk nilai harfiah) secara implisit diberikan jenis oleh kompilator sebelum dievaluasi. Beberapa contoh jenis termasuk jenis bawaan seperti int untuk menyimpan nilai bilangan bulat, double untuk menyimpan nilai floating-point, atau jenis Pustaka Standar seperti kelas std::basic_string untuk menyimpan teks. Anda dapat membuat jenis Anda sendiri dengan menentukan class atau struct. Jenis menentukan jumlah memori yang dialokasikan untuk variabel (atau hasil ekspresi). Jenis ini juga menentukan jenis nilai yang dapat disimpan, bagaimana pengkompilasi menginterpretasikan pola bit dalam nilai-nilai tersebut, dan operasi yang dapat Anda lakukan padanya. Artikel ini berisi gambaran umum informal tentang fitur utama sistem jenis C++.

Terminologi

Jenis skalar: Jenis yang menyimpan satu nilai dari rentang yang ditentukan. Skalar mencakup jenis aritmatika (nilai integral atau titik mengambang), anggota jenis enumerasi, jenis pointer, jenis pointer-to-member, dan std::nullptr_t. Jenis dasar biasanya adalah jenis skalar.

Jenis gabungan: Jenis yang bukan jenis skalar. Jenis majemuk termasuk jenis array, jenis fungsi, jenis kelas (atau struktur), jenis gabungan, enumerasi, referensi, dan pointer ke anggota kelas non-statis.

Variabel: Nama simbolis dari kuantitas data. Nama dapat digunakan untuk mengakses data yang dirujuknya di seluruh cakupan kode tempat kode ditentukan. Dalam C++, variabel sering digunakan untuk merujuk ke instans jenis data skalar, sedangkan instans jenis lain biasanya disebut objek.

Objek: Untuk kesederhanaan dan konsistensi, artikel ini menggunakan objek istilah untuk merujuk ke instans kelas atau struktur apa pun. Ketika digunakan dalam arti umum, itu termasuk semua jenis, bahkan variabel skalar.

Jenis POD (data lama biasa): Kategori informal jenis data di C++ ini mengacu pada jenis skalar (lihat bagian Jenis dasar) atau adalah kelas POD. Kelas POD tidak memiliki anggota data statis yang juga tidak memiliki POD, dan tidak memiliki konstruktor yang ditentukan pengguna, destruktor yang ditentukan pengguna, atau operator penugasan yang ditentukan pengguna. Selain itu, kelas POD tidak memiliki fungsi virtual, tidak ada kelas dasar, dan tidak ada anggota data privat atau non-statis yang dilindungi. Jenis POD sering digunakan untuk pertukaran data eksternal, misalnya dengan modul yang ditulis dalam bahasa C (yang hanya memiliki jenis POD).

Menentukan variabel dan jenis fungsi

C++ adalah bahasa yang di ketik dengan kuat dan bahasa yang ditik secara statis; setiap objek memiliki jenis dan jenis tersebut tidak pernah berubah. Saat Anda mendeklarasikan variabel dalam kode, Anda harus menentukan jenisnya secara eksplisit, atau menggunakan auto kata kunci untuk menginstruksikan pengkompilasi untuk menyimpulkan jenis dari penginisialisasi. Saat Anda mendeklarasikan fungsi dalam kode, Anda harus menentukan jenis nilai pengembaliannya dan setiap argumen. Gunakan jenis void nilai yang dikembalikan jika tidak ada nilai yang dikembalikan oleh fungsi . Pengecualiannya adalah ketika Anda menggunakan templat fungsi, yang memungkinkan argumen jenis arbitrer.

Setelah pertama kali mendeklarasikan variabel, Anda tidak dapat mengubah jenisnya di beberapa titik kemudian. Namun, Anda dapat menyalin nilai variabel atau nilai pengembalian fungsi ke variabel lain dari jenis yang berbeda. Operasi tersebut disebut konversi jenis, yang terkadang diperlukan tetapi juga merupakan sumber potensial kehilangan atau kekeliruan data.

Ketika Anda mendeklarasikan variabel jenis POD, kami sangat menyarankan Anda menginisialisasinya , yang berarti memberinya nilai awal. Sampai Anda menginisialisasi variabel, variabel tersebut memiliki nilai "sampah" yang terdiri dari bit apa pun yang kebetulan berada di lokasi memori itu sebelumnya. Ini adalah aspek penting dari C++ untuk diingat, terutama jika Anda berasal dari bahasa lain yang menangani inisialisasi untuk Anda. Saat Anda mendeklarasikan variabel jenis kelas non-POD, konstruktor menangani inisialisasi.

Contoh berikut menunjukkan beberapa deklarasi variabel sederhana dengan beberapa deskripsi untuk masing-masing. Contoh ini juga menunjukkan bagaimana pengkompilasi menggunakan informasi jenis untuk mengizinkan atau melarang operasi berikutnya tertentu pada variabel.

int result = 0;              // Declare and initialize an integer.
double coefficient = 10.8;   // Declare and initialize a floating
                             // point value.
auto name = "Lady G.";       // Declare a variable and let compiler
                             // deduce the type.
auto address;                // error. Compiler cannot deduce a type
                             // without an intializing value.
age = 12;                    // error. Variable declaration must
                             // specify a type or use auto!
result = "Kenny G.";         // error. Can't assign text to an int.
string result = "zero";      // error. Can't redefine a variable with
                             // new type.
int maxValue;                // Not recommended! maxValue contains
                             // garbage bits until it is initialized.

Jenis dasar (bawaan)

Tidak seperti beberapa bahasa, C++ tidak memiliki jenis dasar universal tempat semua jenis lain diturunkan. Bahasa ini mencakup banyak jenis dasar, juga dikenal sebagai jenis bawaan. Jenis ini mencakup jenis numerik seperti int, , doublelong, bool, ditambah char jenis dan wchar_t untuk karakter ASCII dan UNICODE, masing-masing. Sebagian besar jenis dasar integral (kecuali bool, , doublewchar_t, dan jenis terkait) semuanya memiliki unsigned versi, yang memodifikasi rentang nilai yang dapat disimpan variabel. Misalnya, int, yang menyimpan bilangan bulat bertanda tangan 32-bit, dapat mewakili nilai dari -2.147.483.648 menjadi 2.147.483.647. , unsigned intyang juga disimpan sebagai 32 bit, dapat menyimpan nilai dari 0 hingga 4.294.967.295. Jumlah total nilai yang mungkin dalam setiap kasus sama; hanya rentang yang berbeda.

Pengkompilasi mengenali jenis bawaan ini, dan memiliki aturan bawaan yang mengatur operasi apa yang dapat Anda lakukan padanya, dan bagaimana mereka dapat dikonversi ke jenis dasar lainnya. Untuk daftar lengkap jenis bawaan dan ukuran dan batas numeriknya, lihat Jenis bawaan.

Ilustrasi berikut menunjukkan ukuran relatif dari jenis bawaan dalam implementasi Microsoft C++:

Diagram ukuran relatif dalam byte dari beberapa jenis bawaan.

Tabel berikut mencantumkan jenis dasar yang paling sering digunakan, dan ukurannya dalam implementasi Microsoft C++:

Jenis Ukuran Komentar
int 4 byte Pilihan default untuk nilai integral.
double 8 byte Pilihan default untuk nilai titik mengambang.
bool 1 byte Mewakili nilai yang bisa benar atau salah.
char 1 byte Gunakan untuk karakter ASCII dalam string gaya C yang lebih lama atau objek std::string yang tidak perlu dikonversi ke UNICODE.
wchar_t 2 byte Mewakili nilai karakter "lebar" yang mungkin dikodekan dalam format UNICODE (UTF-16 pada Windows, sistem operasi lain mungkin berbeda). wchar_t adalah jenis karakter yang digunakan dalam string jenis std::wstring.
unsigned char 1 byte C++ tidak memiliki jenis byte bawaan. Gunakan unsigned char untuk mewakili nilai byte.
unsigned int 4 byte Pilihan default untuk bendera bit.
long long 8 byte Mewakili rentang nilai bilangan bulat yang jauh lebih besar.

Implementasi C++ lainnya dapat menggunakan ukuran yang berbeda untuk jenis numerik tertentu. Untuk informasi selengkapnya tentang ukuran dan hubungan ukuran yang diperlukan standar C++, lihat Jenis bawaan.

Jenis void

Jenisnya void adalah jenis khusus; Anda tidak dapat mendeklarasikan variabel jenis void, tetapi Anda dapat mendeklarasikan variabel jenis void * (pointer ke void), yang terkadang diperlukan saat mengalokasikan memori mentah (tidak diketik). Namun, pointer ke void tidak aman jenis dan penggunaannya tidak disarankan dalam C++modern. Dalam deklarasi fungsi, void nilai pengembalian berarti bahwa fungsi tidak mengembalikan nilai; menggunakannya sebagai jenis pengembalian adalah penggunaan umum dan dapat diterima dari void. Sementara bahasa C memerlukan fungsi yang memiliki parameter nol untuk dideklarasikan void dalam daftar parameter, misalnya, , fn(void)praktik ini tidak dianjurkan dalam C++modern; fungsi tanpa parameter harus dideklarasikan fn(). Untuk informasi selengkapnya, lihat Jenis konversi dan keamanan jenis.

const jenis kualifikasi

Jenis bawaan atau yang ditentukan pengguna mungkin memenuhi syarat oleh const kata kunci. Selain itu, fungsi anggota mungkin const-memenuhi syarat dan bahkan const-kelebihan beban. Nilai jenis const tidak dapat dimodifikasi setelah diinisialisasi.

const double PI = 3.1415;
PI = .75; //Error. Cannot modify const variable.

Kualifikasi const digunakan secara ekstensif dalam deklarasi fungsi dan variabel dan "const correctness" adalah konsep penting dalam C++; pada dasarnya itu berarti untuk digunakan const untuk menjamin, pada waktu kompilasi, nilai tersebut tidak dimodifikasi secara tidak sengaja. Untuk informasi selengkapnya, lihat const .

Jenis const berbeda dari non-versinyaconst ; misalnya, const int adalah jenis yang berbeda dari int. Anda dapat menggunakan operator C++ const_cast pada kesempatan langka tersebut ketika Anda harus menghapus const-ness dari variabel. Untuk informasi selengkapnya, lihat Jenis konversi dan keamanan jenis.

Jenis string

Secara ketat, bahasa C++ tidak memiliki jenis string bawaan; char dan wchar_t menyimpan karakter tunggal - Anda harus mendeklarasikan array dari jenis ini untuk memperkirakan string, menambahkan nilai null yang mengakhiri (misalnya, ASCII '\0') ke elemen array satu melewati karakter terakhir yang valid (juga disebut string gaya C). String gaya C membutuhkan lebih banyak kode untuk ditulis atau penggunaan fungsi pustaka utilitas string eksternal. Tetapi dalam C++modern, kita memiliki jenis std::string Pustaka Standar (untuk string karakter 8-bit char-type) atau std::wstring (untuk string karakter 16-bit wchar_t-type). Kontainer Pustaka Standar C++ ini dapat dianggap sebagai jenis string asli karena merupakan bagian dari pustaka standar yang disertakan dalam lingkungan build C++ yang sesuai. Gunakan direktif #include <string> untuk membuat jenis ini tersedia dalam program Anda. (Jika Anda menggunakan MFC atau ATL, CString kelas juga tersedia, tetapi bukan bagian dari standar C++.) Penggunaan array karakter yang dihentikan null (string gaya C yang disebutkan sebelumnya) tidak disarankan dalam C++modern.

Jenis yang ditentukan pengguna

Ketika Anda menentukan classkonstruksi , , structunion, atau enum, yang digunakan dalam sisa kode Anda seolah-olah itu adalah jenis dasar. Ini memiliki ukuran memori yang diketahui, dan aturan tertentu tentang bagaimana hal itu dapat digunakan berlaku untuk pemeriksaan waktu kompilasi dan, pada runtime, untuk masa pakai program Anda. Perbedaan utama antara jenis bawaan dasar dan jenis yang ditentukan pengguna adalah sebagai berikut:

  • Pengkompilasi tidak memiliki pengetahuan bawaan tentang jenis yang ditentukan pengguna. Ini mempelajari jenis ketika pertama kali menemukan definisi selama proses kompilasi.

  • Anda menentukan operasi apa yang dapat dilakukan pada jenis Anda, dan bagaimana operasi dapat dikonversi ke jenis lain, dengan menentukan (melalui kelebihan beban) operator yang sesuai, baik sebagai anggota kelas atau fungsi non-anggota. Untuk informasi selengkapnya, lihat Fungsi kelebihan beban

Jenis pointer

Seperti dalam versi awal bahasa C, C++ terus memungkinkan Anda mendeklarasikan variabel jenis pointer dengan menggunakan deklarator * khusus (tanda bintang). Jenis penunjuk menyimpan alamat lokasi dalam memori tempat nilai data aktual disimpan. Dalam C++modern, jenis pointer ini disebut sebagai pointer mentah, dan diakses dalam kode Anda melalui operator khusus: * (tanda bintang) atau -> (tanda hubung dengan panah yang lebih besar dari, sering disebut panah). Operasi akses memori ini disebut dereferensi. Operator mana yang Anda gunakan bergantung pada apakah Anda mendereferensikan penunjuk ke skalar, atau penunjuk ke anggota dalam objek.

Bekerja dengan jenis pointer telah lama menjadi salah satu aspek paling menantang dan membingungkan dari pengembangan program C dan C++. Bagian ini menguraikan beberapa fakta dan praktik untuk membantu menggunakan pointer mentah jika Anda mau. Namun, dalam C++modern, tidak lagi diperlukan (atau disarankan) untuk menggunakan pointer mentah untuk kepemilikan objek sama sekali, karena evolusi penunjuk pintar (dibahas lebih lanjut di akhir bagian ini). Ini masih berguna dan aman untuk menggunakan pointer mentah untuk mengamati objek. Namun, jika Anda harus menggunakannya untuk kepemilikan objek, Anda harus melakukannya dengan hati-hati dan dengan pertimbangan yang cermat tentang bagaimana objek yang dimiliki oleh mereka dibuat dan dihancurkan.

Hal pertama yang harus Anda ketahui adalah bahwa deklarasi variabel pointer mentah hanya mengalokasikan memori yang cukup untuk menyimpan alamat: lokasi memori yang dirujuk penunjuk ketika didereferensikan. Deklarasi pointer tidak mengalokasikan memori yang diperlukan untuk menyimpan nilai data. (Memori itu juga disebut penyimpanan backing.) Dengan kata lain, dengan mendeklarasikan variabel pointer mentah, Anda membuat variabel alamat memori, bukan variabel data aktual. Jika Anda mendereferensikan variabel penunjuk sebelum memastikan bahwa variabel tersebut berisi alamat yang valid untuk penyimpanan backing, itu menyebabkan perilaku yang tidak ditentukan (biasanya kesalahan fatal) dalam program Anda. Contoh berikut menunjukkan kesalahan semacam ini:

int* pNumber;       // Declare a pointer-to-int variable.
*pNumber = 10;      // error. Although this may compile, it is
                    // a serious error. We are dereferencing an
                    // uninitialized pointer variable with no
                    // allocated memory to point to.

Contoh dereferensi jenis penunjuk tanpa memiliki memori apa pun yang dialokasikan untuk menyimpan data bilangan bulat aktual atau alamat memori valid yang ditetapkan untuknya. Kode berikut mengoreksi kesalahan ini:

    int number = 10;          // Declare and initialize a local integer
                              // variable for data backing store.
    int* pNumber = &number;   // Declare and initialize a local integer
                              // pointer variable to a valid memory
                              // address to that backing store.
...
    *pNumber = 41;            // Dereference and store a new value in
                              // the memory pointed to by
                              // pNumber, the integer variable called
                              // "number". Note "number" was changed, not
                              // "pNumber".

Contoh kode yang dikoreksi menggunakan memori tumpukan lokal untuk membuat penyimpanan cadangan yang pNumber menunjuk ke. Kami menggunakan jenis mendasar untuk kesederhanaan. Dalam praktiknya, penyimpanan pendukung untuk pointer paling sering merupakan jenis yang ditentukan pengguna yang dialokasikan secara dinamis di area memori yang disebut heap (atau toko gratis) dengan menggunakan new ekspresi kata kunci (dalam pemrograman gaya C, fungsi pustaka runtime C yang lebih malloc() lama digunakan). Setelah dialokasikan, variabel ini biasanya disebut sebagai objek, terutama jika didasarkan pada definisi kelas. Memori yang dialokasikan dengan new harus dihapus oleh pernyataan yang delete sesuai (atau, jika Anda menggunakan malloc() fungsi untuk mengalokasikannya, fungsi free()runtime C ).

Namun, mudah untuk lupa menghapus objek yang dialokasikan secara dinamis - terutama dalam kode kompleks, yang menyebabkan bug sumber daya yang disebut kebocoran memori. Untuk alasan ini, penggunaan pointer mentah tidak disarankan dalam C++modern. Hampir selalu lebih baik untuk membungkus pointer mentah dalam pointer pintar, yang secara otomatis melepaskan memori ketika destruktornya dipanggil. (Artinya, ketika kode keluar dari cakupan untuk penunjuk pintar.) Dengan menggunakan penunjuk cerdas, Anda hampir menghilangkan seluruh kelas bug dalam program C++Anda. Dalam contoh berikut, asumsikan MyClass adalah jenis yang ditentukan pengguna yang memiliki metode publik DoSomeWork();

void someFunction() {
    unique_ptr<MyClass> pMc(new MyClass);
    pMc->DoSomeWork();
}
  // No memory leak. Out-of-scope automatically calls the destructor
  // for the unique_ptr, freeing the resource.

Untuk informasi selengkapnya tentang penunjuk cerdas, lihat Penunjuk cerdas.

Untuk informasi selengkapnya tentang konversi pointer, lihat Konversi jenis dan keamanan jenis.

Untuk informasi selengkapnya tentang penunjuk secara umum, lihat Penunjuk.

Jenis data Windows

Dalam pemrograman Win32 klasik untuk C dan C++, sebagian besar fungsi menggunakan typedefs dan #define makro khusus Windows (didefinisikan dalam windef.h) untuk menentukan jenis parameter dan mengembalikan nilai. Jenis data Windows ini sebagian besar adalah nama khusus (alias) yang diberikan untuk jenis bawaan C/C++. Untuk daftar lengkap definisi typedefs dan preprocessor ini, lihat Jenis Data Windows. Beberapa typedef ini, seperti HRESULT dan LCID, berguna dan deskriptif. Lainnya, seperti INT, tidak memiliki arti khusus dan hanya alias untuk jenis C++ mendasar. Jenis data Windows lainnya memiliki nama yang dipertahankan sejak hari pemrograman C dan prosesor 16-bit, dan tidak memiliki tujuan atau makna pada perangkat keras atau sistem operasi modern. Ada juga jenis data khusus yang terkait dengan Pustaka Runtime Windows, yang terdaftar sebagai jenis data dasar Windows Runtime. Dalam C++modern, pedoman umumnya adalah lebih memilih jenis dasar C++ kecuali jenis Windows mengomunikasikan beberapa arti tambahan tentang bagaimana nilai akan ditafsirkan.

Informasi selengkapnya

Untuk informasi selengkapnya tentang sistem jenis C++, lihat artikel berikut ini.

Jenis nilai
Menjelaskan jenis nilai bersama dengan masalah yang berkaitan dengan penggunaannya.

Konversi jenis dan keamanan jenis
Menjelaskan masalah konversi jenis umum dan menunjukkan cara menghindarinya.

Lihat juga

Selamat datang kembali di C++
Referensi bahasa C++
Pustaka Standar C++