Bagikan melalui


Konversi standar

Bahasa C++ mendefinisikan konversi antara jenis dasarnya. Ini juga mendefinisikan konversi untuk jenis turunan pointer, referensi, dan pointer-to-member. Konversi ini disebut konversi standar.

Bagian ini membahas konversi standar berikut:

  • Promosi integral

  • Konversi integral

  • Konversi mengambang

  • Konversi mengambang dan integral

  • Konversi aritmatika

  • Konversi pointer

  • Konversi referensi

  • Konversi pointer-to-member

    Catatan

    Jenis yang ditentukan pengguna dapat menentukan konversi mereka sendiri. Konversi jenis yang ditentukan pengguna tercakup dalam Konstruktor dan Konversi.

Kode berikut menyebabkan konversi (dalam contoh ini, promosi integral):

long  long_num1, long_num2;
int   int_num;

// int_num promoted to type long prior to assignment.
long_num1 = int_num;

// int_num promoted to type long prior to multiplication.
long_num2 = int_num * long_num2;

Hasil konversi adalah nilai l hanya jika menghasilkan jenis referensi. Misalnya, konversi yang ditentukan pengguna yang dinyatakan sebagai operator int&() mengembalikan referensi dan merupakan nilai l. Namun, konversi yang dideklarasikan sebagai operator int() mengembalikan objek dan bukan nilai l.

Promosi integral

Objek dari jenis integral dapat dikonversi ke jenis integral lain yang lebih luas, yaitu jenis yang dapat mewakili sekumpulan nilai yang lebih besar. Jenis konversi yang melebar ini disebut promosi integral. Dengan promosi integral, Anda dapat menggunakan jenis berikut dalam ekspresi di mana pun jenis integral lain dapat digunakan:

  • Objek, literal, dan konstanta jenis char dan short int

  • Jenis enumerasi

  • int bidang bit

  • Enumerator

Promosi C++ adalah "value-preserving", karena nilai setelah promosi dijamin sama dengan nilai sebelum promosi. Dalam promosi yang mempertahankan nilai, objek dari jenis integral yang lebih pendek (seperti bidang bit atau objek jenis char) dipromosikan untuk mengetik int jika int dapat mewakili rentang lengkap jenis asli. Jika int tidak dapat mewakili rentang nilai lengkap, maka objek dipromosikan untuk mengetik unsigned int. Meskipun strategi ini sama dengan yang digunakan oleh Standard C, konversi yang mempertahankan nilai tidak mempertahankan "signedness" objek.

Promosi dan promosi yang mempertahankan nilai yang mempertahankan penandatanganan biasanya menghasilkan hasil yang sama. Namun, mereka dapat menghasilkan hasil yang berbeda jika objek yang dipromosikan muncul sebagai:

  • Operan dari /, %, /=, %=, <, <=, >, atau >=

    Operator ini mengandalkan tanda tangan untuk menentukan hasilnya. Promosi yang mempertahankan nilai dan pelestarian tanda tangan menghasilkan hasil yang berbeda saat diterapkan pada operan ini.

  • Operand kiri dari >> atau >>=

    Operator ini memperlakukan jumlah yang ditandatangani dan tidak ditandatangani secara berbeda dalam operasi shift. Untuk jumlah yang ditandatangani, operasi shift kanan menyebarluaskan bit tanda ke posisi bit yang dikosongkan, sementara posisi bit yang dikosongkan tidak diisi dalam jumlah yang tidak ditandatangani.

  • Argumen ke fungsi kelebihan beban, atau operand operator yang kelebihan beban, yang tergantung pada penandatanganan jenis operand untuk pencocokan argumen. Untuk informasi selengkapnya tentang menentukan operator yang kelebihan beban, lihat Operator kelebihan beban.

Konversi integral

Konversi integral adalah konversi antara jenis integral. Jenis integralnya adalah char, short (atau short int), int, , longdan long long. Jenis-jenis ini dapat memenuhi syarat dengan signed atau unsigned, dan unsigned dapat digunakan sebagai singkatan untuk unsigned int.

Ditandatangani untuk tidak ditandatangani

Objek dari jenis integral yang ditandatangani dapat dikonversi ke jenis yang tidak ditandatangani yang sesuai. Ketika konversi ini terjadi, pola bit aktual tidak berubah. Namun, interpretasi perubahan data. Pertimbangkan kode ini:

#include <iostream>

using namespace std;
int main()
{
    short  i = -3;
    unsigned short u;

    cout << (u = i) << "\n";
}
// Output: 65533

Dalam contoh sebelumnya, signed short, , ididefinisikan dan diinisialisasi ke angka negatif. Ekspresi (u = i) menyebabkan i dikonversi ke sebelum unsigned short penugasan menjadi u.

Tidak ditandatangani untuk ditandatangani

Objek dari jenis integral yang tidak ditandatangani dapat dikonversi ke jenis bertanda tangan yang sesuai. Namun, jika nilai yang tidak ditandatangani berada di luar rentang yang dapat diwakili dari jenis yang ditandatangani, hasilnya tidak akan memiliki nilai yang benar, seperti yang ditunjukkan dalam contoh berikut:

#include <iostream>

using namespace std;
int main()
{
short  i;
unsigned short u = 65533;

cout << (i = u) << "\n";
}
//Output: -3

Dalam contoh sebelumnya, u adalah unsigned short objek integral yang harus dikonversi ke kuantitas yang ditandatangani untuk mengevaluasi ekspresi (i = u). Karena nilainya tidak dapat diwakili dengan benar dalam signed short, data disalahartikan seperti yang ditunjukkan.

Konversi titik mengambang

Objek jenis mengambang dapat dikonversi dengan aman ke jenis mengambang yang lebih tepat—yaitu, konversi tidak menyebabkan hilangnya signifikansi. Misalnya, konversi dari float ke atau dari double ke doublelong double aman, dan nilainya tidak berubah.

Objek jenis mengambang juga dapat dikonversi ke jenis yang kurang tepat, jika berada dalam rentang yang dapat diwakili oleh jenis tersebut. (Lihat Batas Mengambang untuk rentang jenis mengambang.) Jika nilai asli tidak dapat direpresentasikan dengan tepat, nilai tersebut dapat dikonversi ke nilai yang lebih tinggi atau lebih rendah berikutnya yang dapat direpresentasikan. Hasilnya tidak terdefinisi jika tidak ada nilai tersebut. Pertimbangkan contoh berikut:

cout << (float)1E300 << endl;

Nilai maksimum yang dapat diwakili oleh jenis float adalah 3,402823466E38 yang merupakan angka yang jauh lebih kecil daripada 1E300. Oleh karena itu, angka dikonversi menjadi tak terbatas, dan hasilnya adalah "inf".

Konversi antara jenis titik integral dan floating

Ekspresi tertentu dapat menyebabkan objek jenis mengambang dikonversi ke jenis integral, atau sebaliknya. Ketika objek jenis integral dikonversi ke jenis mengambang, dan nilai asli tidak dapat direpresentasikan dengan tepat, hasilnya adalah nilai berikutnya yang lebih tinggi atau lebih rendah berikutnya yang dapat diwakili.

Ketika objek jenis mengambang dikonversi ke jenis integral, bagian pecahan dipotong, atau dibulatkan ke arah nol. Angka seperti 1.3 dikonversi ke 1, dan -1.3 dikonversi ke -1. Jika nilai terpotong lebih tinggi dari nilai tertinggi yang dapat direpresentasikan, atau lebih rendah dari nilai terendah yang dapat direpresentasikan, hasilnya tidak ditentukan.

Konversi aritmatika

Banyak operator biner (dibahas dalam Ekspresi dengan operator biner) menyebabkan konversi operand, dan menghasilkan hasil dengan cara yang sama. Konversi yang disebabkan operator ini disebut konversi aritmatika biasa. Konversi aritmatika operand yang memiliki jenis asli yang berbeda dilakukan seperti yang ditunjukkan dalam tabel berikut. Jenis typedef berperilaku sesuai dengan jenis asli yang mendasarnya.

Kondisi untuk konversi jenis

Kondisi Terpenuhi Konversi
Salah satu operand berjenis long double. Operand lain dikonversi ke jenis long double.
Kondisi sebelumnya tidak terpenuhi dan salah satu operand berjenis double. Operand lain dikonversi ke jenis double.
Kondisi sebelumnya tidak terpenuhi dan salah satu operand berjenis float. Operand lain dikonversi ke jenis float.
Kondisi sebelumnya tidak terpenuhi (tidak ada operan yang bertipe mengambang). Operand mendapatkan promosi integral sebagai berikut:

- Jika salah satu operand berjenis unsigned long, operand lainnya dikonversi ke jenis unsigned long.
- Jika kondisi sebelumnya tidak terpenuhi, dan jika salah satu operand berjenis long dan jenis unsigned intlainnya, kedua operan dikonversi ke jenis unsigned long.
- Jika dua kondisi sebelumnya tidak terpenuhi, dan jika salah satu operand berjenis long, operand lainnya dikonversi ke jenis long.
- Jika tiga kondisi sebelumnya tidak terpenuhi, dan jika salah satu operand berjenis unsigned int, operand lain dikonversi ke jenis unsigned int.
- Jika tidak ada kondisi sebelumnya yang terpenuhi, kedua operan dikonversi ke jenis int.

Kode berikut mengilustrasikan aturan konversi yang dijelaskan dalam tabel:

double dVal;
float fVal;
int iVal;
unsigned long ulVal;

int main() {
   // iVal converted to unsigned long
   // result of multiplication converted to double
   dVal = iVal * ulVal;

   // ulVal converted to float
   // result of addition converted to double
   dVal = ulVal + fVal;
}

Pernyataan pertama dalam contoh sebelumnya menunjukkan perkalian dua jenis integral, iVal dan ulVal. Kondisi yang terpenuhi adalah bahwa tidak ada operan yang berjenis mengambang, dan satu operand berjenis unsigned int. Jadi, operan lainnya, iVal, dikonversi ke jenis unsigned int. Hasilnya kemudian ditetapkan ke dVal. Kondisi yang terpenuhi di sini adalah bahwa satu operand berjenis double, sehingga unsigned int hasil perkalian dikonversi ke jenis double.

Pernyataan kedua dalam contoh sebelumnya menunjukkan penambahan float dan jenis integral: fVal dan ulVal. Variabel ulVal dikonversi ke jenis float (kondisi ketiga dalam tabel). Hasil penambahan dikonversi ke jenis double (kondisi kedua dalam tabel) dan ditetapkan ke dVal.

Konversi pointer

Penunjuk dapat dikonversi selama penugasan, inisialisasi, perbandingan, dan ekspresi lainnya.

Penunjuk ke kelas

Ada dua kasus di mana penunjuk ke kelas dapat dikonversi ke penunjuk ke kelas dasar.

Kasus pertama adalah ketika kelas dasar yang ditentukan dapat diakses dan konversinya tidak ambigu. Untuk informasi selengkapnya tentang referensi kelas dasar yang ambigu, lihat Beberapa kelas dasar.

Apakah kelas dasar dapat diakses tergantung pada jenis warisan yang digunakan dalam derivasi. Pertimbangkan warisan yang diilustrasikan dalam gambar berikut:

Diagram showing an inheritance graph and base class accessibility.

Diagram menunjukkan kelas dasar A. Kelas B mewarisi dari A melalui publik yang dilindungi privat. Kelas C mewarisi dari B melalui B publik.

Grafik pewarisan yang mengilustrasikan aksesibilitas kelas dasar

Tabel berikut menunjukkan aksesibilitas kelas dasar untuk situasi yang diilustrasikan dalam gambar.

Jenis Fungsi Derivasi Konversi dari

B* ke A* legal?
Fungsi eksternal (bukan cakupan kelas) Privat No
Protected No
Publik Ya
Fungsi anggota B (dalam cakupan B) Privat Ya
Protected Ya
Publik Ya
Fungsi anggota C (dalam cakupan C) Privat No
Protected Ya
Publik Ya

Kasus kedua di mana penunjuk ke kelas dapat dikonversi ke penunjuk ke kelas dasar adalah ketika Anda menggunakan konversi jenis eksplisit. Untuk informasi selengkapnya tentang konversi jenis eksplisit, lihat Operator konversi jenis eksplisit.

Hasil dari konversi tersebut adalah penunjuk ke subobjek, bagian objek yang sepenuhnya dijelaskan oleh kelas dasar.

Kode berikut mendefinisikan dua kelas, A dan B, di mana B berasal dari A. (Untuk informasi selengkapnya tentang pewarisan, lihat Kelas Turunan.) Kemudian mendefinisikan bObject, objek jenis B, dan dua pointer (pA dan pB) yang menunjuk ke objek .

// C2039 expected
class A
{
public:
    int AComponent;
    int AMemberFunc();
};

class B : public A
{
public:
    int BComponent;
    int BMemberFunc();
};
int main()
{
   B bObject;
   A *pA = &bObject;
   B *pB = &bObject;

   pA->AMemberFunc();   // OK in class A
   pB->AMemberFunc();   // OK: inherited from class A
   pA->BMemberFunc();   // Error: not in class A
}

Penunjuk pA berjenis A *, yang dapat ditafsirkan sebagai artinya "penunjuk ke objek jenis A." bObject Anggota (seperti BComponent dan BMemberFunc) unik untuk mengetik B dan oleh karena itu tidak dapat diakses melalui pA. Penunjuk pA hanya memungkinkan akses ke karakteristik tersebut (fungsi anggota dan data) objek yang ditentukan di kelas A.

Penunjuk ke fungsi

Penunjuk ke fungsi dapat dikonversi ke jenis void *, jika jenis void * cukup besar untuk menahan penunjuk tersebut.

Penunjuk ke kekosongan

Penunjuk ke jenis void dapat dikonversi ke penunjuk ke jenis lain, tetapi hanya dengan jenis eksplisit yang ditransmisikan (tidak seperti di C). Penunjuk ke jenis apa pun dapat dikonversi secara implisit ke penunjuk untuk mengetik void. Penunjuk ke objek tipe yang tidak lengkap dapat dikonversi ke penunjuk ke void (secara implisit) dan kembali (secara eksplisit). Hasil konversi tersebut sama dengan nilai pointer asli. Objek dianggap tidak lengkap jika dinyatakan, tetapi tidak ada cukup informasi yang tersedia untuk menentukan ukuran atau kelas dasarnya.

Penunjuk ke objek apa pun yang tidak const atau volatile dapat dikonversi secara implisit ke penunjuk jenis void *.

Pointer const dan volatil

C++ tidak menyediakan konversi standar dari const atau volatile jenis ke jenis yang bukan const atau volatile. Namun, konversi apa pun dapat ditentukan menggunakan jenis cast eksplisit (termasuk konversi yang tidak aman).

Catatan

Penunjuk C++ ke anggota, kecuali penunjuk ke anggota statis, berbeda dari pointer normal dan tidak memiliki konversi standar yang sama. Penunjuk ke anggota statis adalah penunjuk normal dan memiliki konversi yang sama dengan penunjuk normal.

konversi pointer null

Ekspresi konstanta integral yang mengevaluasi ke nol, atau ekspresi seperti itu ditransmisikan ke jenis penunjuk, dikonversi ke penunjuk yang disebut penunjuk null. Penunjuk ini selalu membandingkan yang tidak sama dengan penunjuk dengan objek atau fungsi yang valid. Pengecualian adalah penunjuk ke objek berbasis, yang dapat memiliki offset yang sama dan masih menunjuk ke objek yang berbeda.

Di C++11, jenis nullptr harus lebih disukai ke penunjuk null gaya C.

Konversi ekspresi penunjuk

Ekspresi apa pun dengan jenis array dapat dikonversi ke penunjuk dengan jenis yang sama. Hasil konversi adalah penunjuk ke elemen array pertama. Contoh berikut menunjukkan konversi seperti itu:

char szPath[_MAX_PATH]; // Array of type char.
char *pszPath = szPath; // Equals &szPath[0].

Ekspresi yang menghasilkan fungsi yang mengembalikan jenis tertentu dikonversi ke penunjuk ke fungsi yang mengembalikan jenis tersebut, kecuali saat:

  • Ekspresi digunakan sebagai operand ke alamat operator (&).

  • Ekspresi digunakan sebagai operand ke operator panggilan fungsi.

Konversi referensi

Referensi ke kelas dapat dikonversi ke referensi ke kelas dasar dalam kasus ini:

  • Kelas dasar yang ditentukan dapat diakses.

  • Konversi tidak ambigu. (Untuk informasi selengkapnya tentang referensi kelas dasar yang ambigu, lihat Beberapa kelas dasar.)

Hasil konversi adalah penunjuk ke subobjek yang mewakili kelas dasar.

Penunjuk ke anggota

Penunjuk ke anggota kelas dapat dikonversi selama penugasan, inisialisasi, perbandingan, dan ekspresi lainnya. Bagian ini menjelaskan konversi pointer-to-member berikut:

Penunjuk ke anggota kelas dasar

Penunjuk ke anggota kelas dasar dapat dikonversi ke penunjuk ke anggota kelas yang berasal dari kelas tersebut, ketika kondisi berikut terpenuhi:

  • Konversi terbalik, dari penunjuk ke kelas turunan ke penunjuk kelas dasar, dapat diakses.

  • Kelas turunan tidak mewarisi secara virtual dari kelas dasar.

Ketika operand kiri adalah penunjuk ke anggota, operand kanan harus dari jenis pointer-to-member atau menjadi ekspresi konstanta yang mengevaluasi ke 0. Penugasan ini hanya valid dalam kasus berikut:

  • Operand kanan adalah penunjuk ke anggota kelas yang sama dengan operand kiri.

  • Operan kiri adalah penunjuk ke anggota kelas yang diturunkan secara publik dan tidak ambigu dari kelas operand kanan.

penunjuk null ke konversi anggota

Ekspresi konstanta integral yang mengevaluasi ke nol dikonversi ke penunjuk null. Penunjuk ini selalu membandingkan yang tidak sama dengan penunjuk dengan objek atau fungsi yang valid. Pengecualian adalah penunjuk ke objek berbasis, yang dapat memiliki offset yang sama dan masih menunjuk ke objek yang berbeda.

Kode berikut mengilustrasikan definisi pointer ke anggota i di kelas A. Penunjuk, pai, diinisialisasi ke 0, yang merupakan penunjuk null.

class A
{
public:
int i;
};

int A::*pai = 0;

int main()
{
}

Baca juga

Referensi bahasa C++